为什么在 iOS 中使用前导下划线重命名合成属性? [英] Why rename synthesized properties in iOS with leading underscores?

查看:20
本文介绍了为什么在 iOS 中使用前导下划线重命名合成属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能的重复:
cocoa Objective-c 类中变量前面的下划线是如何工作的?

在 Xcode 4 中创建新项目时,样板代码在合成实现文件中的 ivars 时会添加一个下划线字符:

When creating a new project in Xcode 4, the boilerplate code adds an underscore character when it synthesizes the ivars in the implementation file as:

@synthesize window = _window;

或:

@synthesize managedObjectContext = __managedObjectContext;

有人能告诉我这里完成了什么吗?我不是一个完整的 nube,但这是我不理解的 Objective-C 的一个方面.

Can someone tell me what is being accomplished here? I'm not a complete nube, but this is one aspect of objective-C I don't understand.

另一个混淆点;在app的delegate实现中,在如上合成window iVar之后,在应用didFinishLaunchingWithOptions:方法中使用self:

Another point of confusion; in the app delegate implementation, after synthesizing the window iVar as above, in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self:

self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];

但是在 dealloc 方法中它是 _window 或 _viewController

but in the dealloc method it's _window, or _viewController

谢谢

推荐答案

这是以前版本的 Objective-C 运行时的产物.

This is an artifact of a previous version of the Objective-C runtime.

最初,@synthesize 用于创建访问器方法,但运行时仍然要求必须显式实例化实例变量:

Originally, @synthesize was used to create accessors methods, but the runtime still required that instance variables had to be instantiated explicitly:

@interface Foo : Bar {
  Baz *_qux;
}

@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux = _qux;

- (void)dealloc {
  [_qux release];
  [super dealloc];
}

@end

人们会在他们的实例变量前面加上前缀,以将它们与他们的属性区分开来(尽管 Apple 不希望您使用下划线,但那是另一回事).您合成属性以指向实例变量.但重点是,_qux 是一个实例变量,而 self.qux(或 [self qux])是消息 qux 发送到对象 self.

People would prefix their instance variables to differentiate them from their properties (even though Apple doesn't want you to use underscores, but that's a different matter). You synthesize the property to point at the instance variable. But the point is, _qux is an instance variable and self.qux (or [self qux]) is the message qux sent to object self.

我们在-dealloc中直接使用实例变量;使用访问器方法看起来像这样(虽然我不推荐它,原因我将在稍后解释):

We use the instance variable directly in -dealloc; using the accessor method instead would look like this (though I don't recommend it, for reasons I'll explain shortly):

- (void)dealloc {
  self.qux = nil; // [self setQux:nil];
  [super dealloc];
}

这具有释放 qux 以及将引用归零的效果.但这可能会产生不幸的副作用:

This has the effect of releasing qux, as well as zeroing out the reference. But this can have unfortunate side-effects:

  • 您最终可能会触发一些意外通知.其他对象可能正在观察 qux 的变化,当使用访问器方法更改它时会记录这些变化.
  • (并非所有人都同意这一点:)像访问器那样将指针清零可能会隐藏程序中的逻辑错误.如果您在对象被释放之后访问该对象的实例变量,那么您就做错了.然而,由于Objective-C 的nil-消息语义,您永远不会知道,使用访问器设置为nil.如果您直接释放实例变量而不是将引用清零,则访问已释放的对象会导致响亮的EXC_BAD_ACCESS.
  • You may end up firing some unexpected notifications. Other objects may be observing changes to qux, which are recorded when an accessor method is used to change it.
  • (Not everyone agrees on this point:) Zeroing out the pointer as the accessor does may hide logic errors in your program. If you are ever accessing an instance variable of an object after the object has been deallocated, you are doing something seriously wrong. Because of Objective-C's nil-messaging semantics, however, you'll never know, having used the accessor to set to nil. Had you released the instance variable directly and not zeroed-out the reference, accessing the deallocated object would have caused a loud EXC_BAD_ACCESS.

除了访问器方法之外,运行时的更高版本还添加了合成实例变量的功能.使用这些版本的运行时,上面的代码可以省略实例变量:

Later versions of the runtime added the ability to synthesize instance variables in addition to the accessor methods. With these versions of the runtime, the code above can be written omitting the instance variables:

@interface Foo : Bar
@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux = _qux;

- (void)dealloc {
  [_qux release];
  [super dealloc];
}

@end

这实际上在Foo上合成了一个名为_qux的实例变量,它被getter和setter消息-qux-访问setQux:.

This actually synthesizes an instance variable on Foo called _qux, which is accessed by getter and setter messages -qux and -setQux:.

我建议不要这样做:它有点乱,但有一个很好的理由使用下划线;即防止意外直接访问 ivar.如果您认为您可以相信自己会记住您使用的是原始实例变量还是访问器方法,请改为这样做:

I recommend against this: it's a little messy, but there's one good reason to use the underscore; namely, to protect against accidentally direct ivar access. If you think you can trust yourself to remember whether you're using a raw instance variable or an accessor method, just do it like this instead:

@interface Foo : Bar
@property (retain) Baz *qux;
@end

@implementation Foo
@synthesize qux;

- (void)dealloc {
  [qux release];
  [super dealloc];
}

@end

然后,当您想直接访问实例变量时,只需说 qux(在 C 语法中转换为 self->qux,用于从指针).当你想使用访问器方法(它会通知观察者,做其他有趣的事情,并使内存管理更安全和更容易),使用 self.qux ([self qux]) 和 self.qux = blah; ([self setQux:blah]).

Then, when you want to access the instance variable directly, just say qux (which translates to self->qux in C syntax for accessing a member from a pointer). When you want to use accessors methods (which will notify observers, and do other interesting things, and make things safer and easier with respect to memory management), use self.qux ([self qux]) and self.qux = blah; ([self setQux:blah]).

可悲的是,Apple 的示例代码和模板代码很烂.永远不要将其用作正确的 Objective-C 风格的指南,当然也不要将其用作正确的软件架构的指南.:)

The sad thing here is that Apple's sample code and template code sucks. Never use it as a guide to proper Objective-C style, and certainly never use it as a guide to proper software architecture. :)

这篇关于为什么在 iOS 中使用前导下划线重命名合成属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆