Objective-C,如何从另一个类访问实例变量。

7
我习惯用Java编程,并使用类变量来访问其他类中的数据。但是我发现在Obj-C中,类变量的工作方式不同,因此遇到了问题。
我的问题是,在用户登录后,我想在另一个类中访问用户输入的密码。我在不同的论坛和网站上阅读了相关信息,得知应该使用类方法(+)来访问这些数据。但是,由于我需要在第二个类中创建第一类的新实例,这意味着输入的密码不存在于第一类的新实例中。
我的代码如下:
class1.h
@interface class1 : UIViewController {
    UITextField *usernameField;
    UITextField *passwordField;
        UIButton *loginButton;
        NSString *password;
}

@property (nonatomic, retain) IBOutlet UITextField *usernameField;
@property (nonatomic, retain) IBOutlet UITextField *passwordField;
@property (nonatomic, retain) IBOutlet UIButton *loginButton;
@property (nonatomic, retain) NSString *password;

-(IBAction) loginButtonPushed;
+(NSString *)password;

@end

class1.m

#import "viewSwitcherViewController.h"

@implementation viewSwitcherViewController

@synthesize usernameField;
@synthesize passwordField;
@synthesize loginButton;
@synthesize password; // not needed

-(IBAction) loginButtonPushed {
        password = passwordField.text; //not needed
    // ...Code for switching view if successful login... EDITED:
    class2 *c2 = [class2 alloc] init]; //Instantiating new class2 object
    c2.password = passwordField.text; //Assigning tekst from passworField to thePassword-variable in the class2 instance.
}

class2.m

#import "class2.h"
#import "class1.h"

@implementation class2

@synthesize thePassword; //NSString variable

// this method is also not needed
-(void) someMethodUsingPassword {
         class1 *c1 = [[class1 alloc] init];
         thePassword = [c1 password];
         NSLog(@"The password is: %@", thePassword); //This call returns null
}

我的问题是,在Class2中创建的c1实例不保存提交的密码,因此返回“null”。

也许这只是我的Java方法弄错了,但我找不到其他方法,请帮忙解决:)!

4个回答

14
在Java中,公共类变量相当于C和Objective-C中的全局变量。可以这样实现它:
class1.h
class1.h
extern NSString* MyGlobalPassword;

class1.m

NSString* MyGlobalPassword = nil;

那么,任何导入 class1.h 的人都可以读写 MyGlobalPassword

稍微好一点的方法是通过 "类方法" 来使其可访问。

class1.h:

@interface Class1 : UIViewController {
    UITextField *usernameField;
    UITextField *passwordField;
    UIButton *loginButton;    
}
+ (NSString*)password;
@end

class1.m:

static NSString* myStaticPassword = nil;

@implementation Class1
+ (NSString*)password {
    return myStaticPassword;
}

- (void)didClickLoginButton:(id)sender {
    [myStaticPassword release];
    myStaticPassword = [passwordField.text retain];
}

其他类将通过 password 类方法读取密码。

Class2.m:

-(void) someMethodUsingPassword {
     thePassword = [Class1 password]; // This is how to call a Class Method in Objective C
     NSLog(@"The password is: %@", thePassword); 
}

谢谢您可能给出的好答案,但我没有尝试它,因为我自己解决了这个问题。在我的代码示例中遗漏的一点是,在Class1中我实例化了需要密码的class2对象。因此,我可以通过访问在class1中创建的实例来简单地设置class2中的密码变量。我将编辑我的代码,以便其他人可以看到我是如何解决它的。 - Aleksander Akerø
+1 给使用类方法的“稍微更好的方法”。不错! - Sam Spencer

5

您应该重新考虑您的应用程序结构设置。您的基本需求是需要在一个类中保存密码并在另一个类中访问它,对吗?使用NSUserDefaults就可以实现这个需求(几乎完美,见下面的注释#3)。将您的class1代码更改为以下内容:

-(IBAction) loginButtonPushed {
    NSString *username = self.usernameField.text;
    NSString *password = self.passwordField.text;

    // Do your login stuff here, if successful do the following
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefauls];
    [defaults setObject:username forKey:@"usernameKey"];
    [defaults setObject:password forKey:@"passwordKey"];
}

删除您的密码属性,现在您不需要它。此外,删除您的+(NSString *)password;方法。

当您需要访问登录名和密码时:

-(void) someMethodUsingPassword {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefauls];
    NSString *username = [defaults stringForKey:@"usernameKey"];
    NSString *password = [defaults stringForKey:@"passwordKey"];

    // do whatever here
}

一些注意事项

  1. 我是凭记忆写的,所以如果你发现任何错误,请告诉我,我会更新我的答案。
  2. 关于如何使用类方法和属性,您似乎缺少一些关键点。我强烈建议阅读苹果公司的Objective-C入门指南
  3. NSUserDefaults中存储登录和密码信息并不安全。如果有人获得了您设备或设备备份的root访问权限,他们可能能够提取此登录信息。如果安全对您至关重要,请将登录信息存储在Keychain中。

我从其他博客文章和Objective-C文献中了解到,不应该使用NSUserDefaults存储密码,因为它不安全,需要加密。此外,我不需要保存密码,只需要将其从一个类传递到另一个类。 - Aleksander Akerø

2
class2中创建的class1不会设置密码,因为您只是使用[[class1 alloc] init]实例化了一个新实例 - 这不会与其他地方创建的class1实例共享成员变量。

是的,其实我在我的问题中已经解释过了,但感谢你澄清:)也许只是解释得有些草率:P - Aleksander Akerø

1

一般来说,

当您在一个屏幕中接受密码并对其进行操作时,您仍然拥有它。 当您移动到其他屏幕时,为什么不将class1的对象作为class2中的属性保留,并在将控件传递给class2之前设置它。

或者,如果您只是调用class2的方法,请将已经包含密码的class1对象作为参数传递。

如果您只是将其作为参数传递给该方法,则可以访问它。 或者,如果您将其设置为此class2的属性。 那么您始终可以使用getter。

这件事与Java或Objective C无关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接