我正在尝试从我的第一个ViewController传递一个字符串到我的第二个ViewController,但它返回NULL

时间:2012-11-26 00:49:02

标签: iphone ios xcode string

在我的第一个视图控制器中,我有3个输入字段,每个输入字段都将用户输入并将其保存到字符串中,例如:地址,用户名和密码为NSUserDefaults。这部分工作正常。 在我的第二个视图控制器中,我试图从第一个控制器(地址,用户名和密码)中取出3个字符串,根据3个字符串创建一个html链接。我已经尝试了很多方法来访问3个字符串而没有运气,我得到的结果是NULL。 这是我的代码:

//。h file - 具有3个输入字段CamSetup.h

的第一个视图控制器
 #import <UIKit/UIKit.h>
 @interface CamSetup : UIViewController <UITextFieldDelegate> 
 {
    NSString * address;
    NSString * username;
    NSString * password;

    IBOutlet UITextField * addressField;
    IBOutlet UITextField * usernameField;
    IBOutlet UITextField * passwordField; 
 }

 -(IBAction) saveAddress: (id) sender;
 -(IBAction) saveUsername: (id) sender;
 -(IBAction) savePassword: (id) sender;

 @property(nonatomic, retain) UITextField *addressField;
 @property(nonatomic, retain) UITextField *usernameField;
 @property(nonatomic, retain) UITextField *passwordField; 
 @property(nonatomic, retain) NSString *address; 
 @property(nonatomic, retain) NSString *username; 
 @property(nonatomic, retain) NSString *password;

 @end

//。m file - 第一个视图控制器CamSetup.m

#import "CamSetup.h"

@interface CamSetup ()
@end

@implementation CamSetup
@synthesize addressField, usernameField, passwordField, address, username, password;

-(IBAction) saveAddress: (id) sender
{
address = [[NSString alloc] initWithFormat:addressField.text];
[addressField setText:address];
NSUserDefaults *stringDefaultAddress = [NSUserDefaults standardUserDefaults];
[stringDefaultAddress setObject:address forKey:@"stringKey1"];
NSLog(@"String [%@]", address);
}

-(IBAction) saveUsername: (id) sender
{
  username = [[NSString alloc] initWithFormat:usernameField.text];
  [usernameField setText:username];
  NSUserDefaults *stringDefaultUsername = [NSUserDefaults standardUserDefaults];
  [stringDefaultUsername setObject:username forKey:@"stringKey2"];
  NSLog(@"String [%@]", username);
}

-(IBAction) savePassword: (id) sender
{
  password = [[NSString alloc] initWithFormat:passwordField.text];
  [passwordField setText:password];
  NSUserDefaults *stringDefaultPassword = [NSUserDefaults standardUserDefaults];
  [stringDefaultPassword setObject:password forKey:@"stringKey3"];
  NSLog(@"String [%@]", password);
}

- (void)viewDidLoad
{   
[addressField setText:[[NSUserDefaults standardUserDefaults] objectForKey:@"stringKey1"]];
[usernameField setText:[[NSUserDefaults standardUserDefaults] objectForKey:@"stringKey2"]];
[passwordField setText:[[NSUserDefaults standardUserDefaults] objectForKey:@"stringKey3"]];

[super viewDidLoad];
}

@end

//。第二个视图控制器LiveView.h

 #import <UIKit/UIKit.h>
 #import "CamSetup.h"
 @interface LiveView : UIViewController
 {
  NSString *theAddress;
  NSString *theUsername;
  NSString *thePassword;
  CamSetup *camsetup; //here is an instance of the first class
}
@property (nonatomic, retain) NSString *theAddress;
@property (nonatomic, retain) NSString *theUsername;
@property (nonatomic, retain) NSString *thePassword;

@end

//。第二个视图LiveView.m文件

#import "LiveView.h"
@interface LiveView ()
@end

@implementation LiveView
@synthesize theAddress, theUsername, thePassword;

- (void)viewDidLoad
{
  [super viewDidLoad]; 
  theUsername = camsetup.username; //this is probably not right?
  NSLog(@"String [%@]", theUsername); //resut here is NULL
  NSLog(@"String [%@]", camsetup.username); //and here NULL as well
}
@end

5 个答案:

答案 0 :(得分:2)

此代码中有5个问题:

  1. 如果您使用ARC,则@properties中的所有“保留”都应更改为“strong”
  2. 您将iVars和属性命名为相同的内容。 (常见的不良做法)
  3. 您总是直接访问iVars而不是代码中的属性。
  4. 您不会在第二个对象中保留CamSetup实例。
  5. 问题的直接原因:在第二个对象中,您只为CamSetup实例创建了一个占位符,您没有创建一个占位符,也没有传递给它!你的第二个对象中的self.camSetup现在是空的。
  6. 让我们一步一步走:

    首先,从您的属性中为您的iVars提供不同的名称。这是最佳实践,尤其对初学者而言! :)

    @interface CamSetup : UIViewController <UITextFieldDelegate> 
    {
        NSString *_address;
    }
    @property(nonatomic, strong) NSString *address;
    @end
    
    @implementation CamSetup
    @synthesize address=_address;
    ...
    @end
    

    这很重要,因为您已经设置了属性,但在您的代码中,您没有使用它们,而是直接访问您的iVars。既然你把它们命名为同一个东西,你可能看不到这个。

    让我们看看你的第一个对象。代码中的每个“地址”都会转到您的iVar,而不是属性。通常,您希望通过您的属性访问iVars,除非您确定不这样做。 @synthesize为你的iVar创建一个getter和setter方法,它将保留var,因为你在@property语句中告诉了它。但是,当您直接访问iVar时,您不会通过这些访问器,因此您在@properties中编写的内容无关紧要。如果您不清楚这一点,最终可能会误解许多错误和错误。在你的第一个对象中,无论如何都有效,因为alloc / init在对象上设置了一个保留,但是我注意到你总是这样做,这会让你遇到麻烦。

    以下是使用属性的saveAddress:方法:

    -(IBAction) saveAddress: (id) sender
    {
       self.address = [[NSString alloc] initWithFormat:self.addressField.text];
       [self.addressField setText:self.address];
       NSUserDefaults *stringDefaultAddress = [NSUserDefaults standardUserDefaults];
       [stringDefaultAddress setObject:self.address forKey:@"stringKey1"];
       NSLog(@"String [%@]", self.address);
    }
    

    接下来,在第二个对象中,您需要设置CamSetup实例的属性!现在,你只有一个iVar。

     #import <UIKit/UIKit.h>
     #import "CamSetup.h"
     @interface LiveView : UIViewController
     {
      NSString *_theAddress;
      NSString *_theUsername;
      NSString *_thePassword;
      CamSetup *_camSetup; //here is an instance of the first class
    }
    @property (nonatomic, retain) CamSetup *camSetup; // in synthesize we'll specify that this property uses the _camSetup iVar
    @property (nonatomic, strong) NSString *theAddress;
    @property (nonatomic, strong) NSString *theUsername;
    @property (nonatomic, strong) NSString *thePassword;
    
    @end
    

    实施:

    #import "LiveView.h"
    @interface LiveView ()
    @end
    
    @implementation LiveView
    @synthesize camSetup = _camSetup;
    @synthesize theAddress = _theAddress;
    @synthesize theUsername = _theUsername;
    @synthesize thePassword = _thePassword;
    
    - (void)viewDidLoad
    {
      [super viewDidLoad]; 
      self.theUsername = self.camSetup.username; //this is probably not right?
      // well, it's better now, but where is camSetup coming from??? it's undefined now
      NSLog(@"String [%@]", self.theUsername); //resut here is NULL
      NSLog(@"String [%@]", self.camSetup.username); //and here NULL as well
    }
    @end
    

    我们已经创建了一个iVar和属性对,它将保存一个指向CamSetup实例的指针并保留该指针(如果我们使用该属性设置它)。但是,创建CamSetup实例的位置在哪里?你在哪里分配/初始化它?

    这个问题有很多可能的答案。如果CamSetup有地址,用户名,密码的getter从你的用户默认值读回来,那么你所要做的就是分配/初始化一个CamSetup并将其设置为camSetup。但是,现在您的第一个对象没有检索已保存数据的功能,因此我们无法执行此操作。 (仍然,这是我希望你实施的解决方案。)

    您可能正在应用代理中初始化这两者?但是,如果您正在使用故事板,则可能是在初始化界面时为您初始化这些对象。在这种情况下,在您的appDelegate应用程序已完成启动...方法时,您必须检索指向这些实例的指针,然后检索第二个对象上的camSetup属性,指向第一个。要告诉您如何执行此操作,我们必须了解您的应用的详细信息。不过,这不会是最好的方式。

    最佳做法是创建一个对象,为您保存和检索用户默认值中的这些数据。如果您以后想要更改存储这些数据的方式,此未来将证明您的实施。您只需更改它们在类中存储/检索的方式。

答案 1 :(得分:1)

你的问题在这里:

CamSetup *camsetup; //here is an instance of the first class 

您没有做任何事情让camsetup引用从用户那里获取输入的CamSetup类的相同实例。 camsetup变量永远不会被初始化,因此它是NULL,因此您尝试从中检索的任何属性也将为NULL。

你究竟如何解决这个问题取决于程序的结构。一种可能性是让任何代码创建LiveView控制器设置camsetup值。例如:

LiveView *liveViewController  = [LiveView alloc] initWithNibName:@"LiveView" bundle:nil]];
liveViewController.camsetup = camSetupController;

(您需要使camsetup属性才能执行此操作。)

但是,从设计的角度来看,让一个视图控制器引用另一个视图控制器可能是解决这个问题的错误方法 - 它会在两个控制器之间引入不必要的依赖关系。例如,假设您稍后决定使用保存的名称/密码在程序启动时直接转到LiveView控制器;如果LiveView依赖于从CamSetup对象获取其输入,则无法执行此操作。

因此,更好的方法可能是让LiveViewNSUserDefaults获取输入,和/或让调用LiveView的代码设置用户名/密码属性。

- 编辑 -

例如,从用户默认值中检索数据,如:

self.address = [[NSUserDefaults standardUserDefaults] objectForKey:@"stringKey1"];

答案 2 :(得分:0)

camsetup是否已初始化?如果不是 - 首先将其初始化。

答案 3 :(得分:0)

有很多方法可以做到这一点,其中大部分都取决于两个控制器如何相互关联(比如你从第一个到第二个如何)。

但是,在您的情况下,您根本不需要传递字符串,因为您将它们保存在用户默认值中。只需在第二个控制器中读取这些默认值即可。

答案 4 :(得分:0)

嗨,我的问题只是做了一件事。 当您在NSUserDefaults中设置值时,它需要synchronization,所以只需synchronize

[stringDefaultUsername synchronize];  

使用

检索数据
NSString *username =  [[NSUserDefaults standardUserDefaults] objectForKey:@"stringKey2"];

关注苹果NSUserDefaults Class Reference了解更多信息