为什么要重命名带有下划线的iOS中的合成属性? [英] Why rename synthesized properties in iOS with leading underscores?

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

问题描述


可能重复:

可变目标c类中变量前面的下划线如何工作? / p>

在Xcode 4中创建新项目时,样板代码会在合成ivars在实现文件中:

  @synthesize window = _window; 

或:

 code> @synthesize managedObjectContext = __managedObjectContext; 

有人能告诉我在这里完成了什么吗?我不是一个完整的nube,但这是目标C的一个方面我不明白。



另一个混乱点;在应用程序代理实现中,在合成如上所述的窗口iVar之后,在应用程序didFinishLaunchingWithOptions:方法中,窗口和viewController ivars使用self引用:

 code> self.window.rootViewController = self.viewcontroller 
[self.window makeKeyAndVisible];

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



感谢

解决方案

这是Objective-C运行时的以前版本的工件。



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

  @interface Foo:Bar {
Baz * _qux;
}

@property(retain)Baz * qux;
@end

@implementation Foo
@synthesize qux = _qux;

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

@end

以区分他们的属性(即使苹果不想让你使用下划线,但这是一个不同的事情)。您合成属性以指向实例变量。但关键是, _qux 是一个实例变量, self.qux (或 qux] )是发送给对象 self 的消息 qux



我们直接在 -dealloc 中使用实例变量;使用访问器方法代替看起来像这样(虽然我不推荐它,因为我会很快解释):

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

这会释放 qux ,以及清零引用。但这可能会产生不良的副作用:




  • 您最终可能会触发一些意外通知。其他对象可能正在观察对 qux 的更改,这些更改在使用访问器方法更改时记录。

  • (不是每个人都同意在这一点上:)归零指针作为访问器可能会隐藏您的程序中的逻辑错误。如果您在访问 之后的对象的实例变量 之后,该对象已被取消分配,则您正在做严重错误的操作。因为Objective-C的 nil - 消息语义,但是,你永远不会知道,使用访问器设置为 nil 。如果你直接释放了实例变量,并且没有清除引用,则访问释放对象会产生大量的 EXC_BAD_ACCESS



后来版本的运行时增加了除了访问器方法之外合成实例变量的能力。使用这些版本的运行时,上面的代码可以省略实例变量来写:

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

@implementation Foo
@synthesize qux = _qux;

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

@end

这实际上合成了一个实例变量on Foo 调用 _qux ,可通过getter和setter消息访问 -qux -setQux:



我建议反对:这有点凌乱,好的原因使用下划线;即,防止意外直接ivar接入。如果你认为你可以相信自己记住你是使用原始的实例变量还是访问器方法,只需这样做:

  @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 ] )。



这里的可悲的是苹果的示例代码和模板代码糟透了。不要使用它作为适当的Objective-C风格的指南,并且绝对不要使用它作为正确的软件架构的指南。 :)


Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?

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;

or:

@synthesize managedObjectContext = __managedObjectContext;

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.

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];

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

Thanks

解决方案

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

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

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.

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];
}

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

  • 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

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

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

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]).

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天全站免登陆