关于iphone:Objective-C:_variable

Objective-C: _variable

好吧,这肯定是以前问过的,但我看起来很生气,什么也没发现:

我的iPhone应用程序中有一个简单的数组,我定义如下:

1
2
@property (nonatomic, strong) NSArray *pages;
@synthesize pages = _pages;

我在Apples示例代码中看到了这一点,并认为这是编写self.pages(即,使用页面替换self.pages)的一个很好的捷径,如下所示:

1
_pages = [[NSArray alloc] init];

但苹果又有了这个(不完全是这样,但看起来好像他们一直在随机交换):

1
self.pages = [NSKeyedUnarchiver unarchiveObjectWithData:contents];

最后:

1
[_pages release];

这让我很困惑。页面和self.pages有什么区别?

谢谢你的帮助。


_pages是对象的ivar的名称。pages是不同的属性名。因此,@synthesize pages = _pages;最后告诉我们,pages是ivar _pages的财产。

您将在初始值设定项和dealloc方法中通过_pages实现ivar直接访问。每隔一个地方,属性名都用于获取/设置其值。


这种差异来自于常见的命名和使用实践。

实例变量和属性都引用同一对象。命名差异用于指出ivar(_pages和属性(pages之间的差异。

ivar由类的实例拥有,由它们来处理它的所有权操作(alloc、retain、release等)。通常,这些所有权操作发生在initdealloc中。

另一方面,该属性为IVAR提供"指定"访问点。属性方法(setter和getter)可以执行适当管理ivar所需的其他操作。因此,不建议直接访问ivar(作为一种使用模式),即使在拥有的对象中也是如此。例如,可以这样实现setter:

1
2
3
4
5
6
7
8
9
- (void) setPages:(NSArray *)newValue {
    [newValue retain];

    // additional operations that you will miss if you use the ivar
    [someObject someUsefulOperationThatIsReallyNeeded];

    [pages release];
    _pages = newValue;
}


当您使用简单的分配时:

页=…

只需设置实例变量。

使用财产转让时:

self.pages=…

它调用由编译器自动合成的方法(或由您定义的方法),为了合成此方法,它检查属性的类型(retain、assign,…)并编写与此类型属性匹配的代码。


_pages是实例变量,pages是属性名。属性通过getter和setter方法pagessetPages:object.pages等同于[object pages]或例如`[self-setpages:[nskeedunarchiveobjectwitdata:contents]访问;

因此,唯一实际的对象是实例变量_pages,因此只有这个变量可以进行内存管理。

实际上,属性和合成器代码给出的代码与此代码相同(实际上,内存管理和线程锁定可能需要额外的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@interface MyClass
{
 ...
    NSArray *_pages
}

- (NSArray*)pages;
- (void)setPages:(NSArray*)newValue;

@end

@implementation MyClass
- (NSArray*)pages
{
    return _pages;
}
- (void)setPages:(NSArray*)newValue
{
    _pages = newValue; // Note in non ARC code there would be some memort managment here
}

@end

您可以将@synthesized属性引用为instanceVariableNameself.propertyName。两个名称可以相同或不同。

当您引用为instanceVariableName并修改该值时,没有应用关联属性的保留/复制逻辑——您只是引用了"raw"变量。当您引用self.propertyName时,将应用保留/复制逻辑,例如,如果属性声明为"保留",则将释放旧值并保留新值。

将已保留的值(如alloc/init中的一个)分配给属性时,将该值分配给instanceVariableName并跳过对release的需要(这样,retains的净值在操作结束时将为1),会更简单(如果这是一个属性以前为nil的初始化)。但是,当将一个非retained的值(autoreleasedretain除外)分配给一个属性时,您希望该属性的retain发生,因此您将使用self.propertyName符号。

使用前导"uu"作为实例变量也是一个属性,这是保持这两个变量分开的简单约定,并且避免在您指另一个变量时意外引用一个变量(通过错误地添加/删除self)。