何时应该使用“self”关键字?

9
我在开发iPhone应用时,什么情况下应该使用self表达式?比如我有两个字段:UITextField *text1;NSString *str1; 都被保留和合成了。
当我访问这两个字段时,什么情况下应该使用self.text1self.str1,什么情况下不应该使用呢?
6个回答

8

self 不是一个关键字,它是一个表达式。此外,你可以在任何时候使用它来引用自己的方法或属性,或者直接引用自己。当我说“自己”时,当然是指你正在操作的类的实例。


1
所以看起来它与Java的this表达式完全相同,除非涉及具有相同名称的变量,否则通常不是必需的。 - james
12
一个重要的区别是,self.str1 = @"abc" 会使用访问器方法 (setStr1:),但 str1 = @"abc" 不会。在使用带有 retain 属性的属性时,这个区别非常关键。因此,它真的不是 "和 Java 中的 this 完全相同"。 - David Gelhar

7
在某些情况下,通常不建议使用self.表达式来访问属性。一般情况下,您总是使用self来访问任何属性。这是最安全和简单的方法。特别是如果您使用了retain,那么内存管理将由系统自动完成。
有两个例外:
1. 任何init方法。 2. 在dealloc中。
在这两种情况下,您正在处理一个部分初始化的对象。在这里使用setter或getter可能会产生一些副作用,因为它们是方法,因此可能被覆盖。
例如,假设有一个名为A的类,它有一个名为foo的属性,被类B继承。子类B添加了一个属性bar并重写了foo的setter。现在,您的init方法调用setFoo:,因为您使用了self.foo = ...来设置初始值。然而,子类在此setter中也访问了bar的值。但在这种情况下,可能会发生bar从未被初始化并指向某些任意数据的情况。在init中调用setter可能会导致崩溃,尽管在您自己的代码中概率不会太高。

6
在你的例子中,当你使用self时,你并没有直接访问实例变量,而是在访问你所定义的属性。
看下面这个例子:
@interface Foo : NSObject {
   NSString *_bar;
}

@property (nonatomic, retain) NSString *bar;

@end

@implementation Foo
@synthesize bar = _bar;
-(void)baz {
   _bar = @"ivar";  //accessing the ivar
   self.bar = @"property"; //accessing the ivar via the property
}

@end

通常情况下,如果您使用属性,则很少需要使用实例变量(ivar)。这样做的另一个好处是自动为您保留和释放值。

但是,在某些情况下,您的属性将具有readonly修饰符。在这些情况下,需要直接访问实例变量以设置其值。


我有点困惑。_foo和foo在哪里声明?在你的baz方法中,它们真的应该是_bar和bar吗? - Wade Mueller

5

有时,在方法调用中使用self是一个好主意,特别是如果你有一个自定义getter。在使用Core Data的应用程序中,managedContext对象是一个很好的例子。如果通过self.managedContext进行引用,如果它是nil,你可以重写并设置对象为所需值。参考使用Core Data创建应用程序时由XCode生成的代码。

这是XCode生成的代码示例:

@interface YourAppDelegate : NSObject <UIApplicationDelegate>
{
@private
    NSManagedObjectContext *managedObjectContext_;
}


@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;



@implementation ContractionTimerAppDelegate

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
 */
- (NSManagedObjectContext *)managedObjectContext {

    if (managedObjectContext_ != nil) {
        return managedObjectContext_;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext_ = [[NSManagedObjectContext alloc] init];
        [managedObjectContext_ setPersistentStoreCoordinator:coordinator];
    }
    return managedObjectContext_;
}

@end

1

如果你使用"synthesize"合成变量,你应该在变量前加上"self."。这是一个小技巧。


0

我对Objective-C一无所知,但这看起来很像其他语言(如C++、C#、Java、PHP等)中的this关键字。如果是这样的话,我的建议是始终使用它。这样,如果您(意外地)定义了一个同名的局部变量,您的代码不会出错。

然而,我还必须补充说,这在程序员社区中是一场有争议的宗教战争的历史。因此,请带着一颗谨慎的心接受这个建议,并使用任何对您最有意义的东西。只要保持一致即可。


但请注意,这不仅是Objective-C中的样式/可维护性问题 - 当使用具有getter/setter方法的属性时,省略“self”会绕过getter/setter; 这是一个真正的语义差异。 - David Gelhar
这正是我所寻找的,很棒。 - james
@David Gelhar - 抱歉。我告诉过你我不知道。:P - Vilx-

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