【发布时间】:2012-05-21 00:59:43
【问题描述】:
我不明白这个,除非是因为我释放的是财产而不是 ivar。有人能解释一下这个问题吗?
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
[self.dataToBeLoaded release];
警告是Incorrect decrement of the reference count of an object that is not owned by the caller。
dataToBeLoaded 属性具有与其设置器关联的保留属性。
我的理解是 alloc init 增加了保留计数,而属性分配增加了保留计数。由于我只有一个保留它一次,所以我在分配后立即释放它。
更新——一些实验结果:
由于我在下面的 cmets 中注意到我收到了关于保留属性对合成设置器的作用的相互矛盾的建议,我想我会使用上面的代码做一个小实验,并通过一些日志记录进行修改:
NSLog(@"retain 1 = %d", [dataToBeLoaded_ retainCount]);
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 2 = %d", [dataToBeLoaded_ retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [dataToBeLoaded_ retainCount]);
每个日志语句的结果是0、2和1。
显然,无法进入 alloc 或 init 代码来查看保留计数从 0 到 1 到 2。我可以将 NSMutableData 类子类化,但我的时间很短。
我知道很多人说你不能依赖 retainCount 属性的值,但我所拥有的似乎是一致的,我希望在示例中显示的代码的短范围内有合理的行为。所以我倾向于相信之前的建议是正确的——retain 属性是一个在 setter 中包含一个 retain 的承诺。所以在这里我有来自 alloc/init 的保留和来自对 setter 的调用的保留。因此,保留计数设置为 2。
当我运行这段代码时:
NSMutableData *theData;
NSLog(@"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(@"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [theData retainCount]);
每个日志语句的保留计数为 0、1、2、1。
所以我有证据表明二传手提供了retain。这似乎更像是一个承诺而不是一个暗示,因为它实际上正在发生。
我愿意接受其他解释。我不想在这件事上傲慢自大。我只是想弄清楚正在发生的事情。我似乎认为警告(在这个问题的主题中)确实是虚假的,不需要担心。
另一个实验是使用assign 而不是retain 作为@property 语句中的属性。使用相同的代码:
NSMutableData *theData;
NSLog(@"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(@"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [theData retainCount]);
每条日志的retain count是0、1、1(setter没有retain),则报错:message sent to deallocated instance。上一个版本将保留计数设置为零,这触发了释放。
更新 2
最后一次更新——当合成的 setter 被您自己的代码覆盖时,将不再观察到 retain 属性,除非您的 setter 明确包含它。显然(这与我在其他线程中被告知的内容相矛盾)如果这是你想要的,你必须在 setter 中包含你自己的保留。虽然我这里没有测试,但你可能需要先释放旧实例,否则它会被泄露。
此自定义 setter 不再具有 @propety 声明的属性属性:
- (void) setDataToBeLoaded:(NSMutableData *)dataToBeLoaded {
dataToBeLoaded_ = dataToBeLoaded;
}
这是有道理的。覆盖一个综合的设置器,你会覆盖所有声明的属性。使用合成的 setter,在合成的实现中观察到声明的属性。
@property 属性表示关于如何实现合成设置器的“承诺”。编写自定义设置器后,您就可以自己动手了。
【问题讨论】:
标签: ios memory-management