Why rename synthesized properties in iOS with leading underscores?
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
在xcode 4中创建新项目时,样板代码在实现文件中合成ivar时添加下划线字符,如下所示:
1 | @synthesize window = _window; |
或:
1 | @synthesize managedObjectContext = __managedObjectContext; |
有人能告诉我这里正在做什么吗?我不是一个完美无缺的人,但这是客观C的一个方面,我不明白。
另一个困惑点是:在应用程序委托实现中,在如上所述合成窗口ivar后,在应用程序didFinishLaunchingWithOptions:方法中,使用self引用窗口和viewController ivar:
1 2 | self.window.rootViewController = self.viewController [self.window makeKeyAndVisible]; |
但在dealloc方法中,它是窗口,或视图控制器
谢谢
这是Objective-C运行时早期版本的工件。
最初,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @interface Foo : Bar { Baz *_qux; } @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end |
人们会给他们的实例变量加前缀以区别于它们的属性(即使苹果不希望你使用下划线,但这是另一回事)。您合成属性以指向实例变量。但重点是,
我们直接在
1 2 3 4 | - (void)dealloc { self.qux = nil; // [self setQux:nil]; [super dealloc]; } |
这有释放
- 您最终可能会触发一些意外的通知。其他对象可能正在观察
qux 的变化,当使用访问器方法更改它时会记录这些变化。 - (并非每个人都同意这一点:)将指针归零,因为访问器会隐藏程序中的逻辑错误。如果在对象解除分配后访问对象的实例变量,则说明您做了严重错误的事情。但是,由于Objective-C的
nil 消息传递语义,您永远不会知道,使用了访问器将设置为nil 。如果您直接释放实例变量而不将引用归零,那么访问释放的对象将导致一个很大的EXC_BAD_ACCESS 。
运行时的更高版本增加了除访问器方法之外合成实例变量的能力。使用这些版本的运行时,可以省略实例变量来编写上面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end |
这实际上是在
我建议不要这样做:这有点混乱,但有一个很好的理由使用下划线;即,防止意外地直接访问ivar。如果您认为您可以相信自己记住是使用原始实例变量还是访问器方法,只需这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux; - (void)dealloc { [qux release]; [super dealloc]; } @end |
然后,当您想直接访问实例变量时,只需说
令人遗憾的是,苹果的示例代码和模板代码太差劲了。不要将它用作正确的Objective-C风格的指南,也不要将它用作正确的软件架构的指南。:)
这是另一个原因。在不强调实例变量的情况下,您经常使用参数
1 2 3 4 5 6 7 8 9 10 11 | @implementation ScaryBugData @synthesize title; @synthesize rating; - (id)initWithTitle:(NSString *)title rating:(float)rating { if (self = [super init]) { self.title = title; // Warning. Local declaration hides instance variable self.rating = rating; // Warning. Local declaration hides instance variable } return self; } @end |
您可以通过突出显示实例变量来避免警告:
1 2 3 4 5 6 7 8 9 10 11 | @implementation ScaryBugData @synthesize title = _title; @synthesize rating = _rating; - (id)initWithTitle:(NSString *)title rating:(float)rating { if (self = [super init]) { self.title = title; // No warning self.rating = rating; // No warning } return self; } @end |
in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self
不,他们不是。这些是对
是的,它只是为了区分对象的引用。也就是说,如果直接引用对象,则使用它和下划线,否则使用self引用对象。