我敢打赌,我可以通过阅读类似的帖子或通过谷歌搜索来找到这个问题的答案,但我希望第一手“听到”它可以说,因为这是我理解中的一个异常。
所以这就是事情,我有一些前任员工编写的代码,我看到很多某种类型的构造对我来说看起来很奇怪,我只想澄清什么是“对与错”。
例如
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
此处wwanServiceId
是该班级的NSString
成员,对我而言,这似乎是一种奇怪的方式。据我所知,它会首先在对象上放一个autorelease
,基本上说:“每当这个对象好像不被使用时,为我发布它我并不在乎”然后副本就会出现保留计数+1 .... wwanServiceId?还是newValue?我想是第一个。
然后让我更加困惑让我们快速浏览wwanServiceId
的生命周期 - 字符串..
如果我们收到通知,然后通知处理程序方法将调用上述-setWwanServiceId:
方法,则基本上会设置该值。除此之外,它只会被阅读,所以我们可以肯定地说它会在任何给定的点上:
然后还有一个怪癖,这是我变得相当可疑的地方,即-dealloc
方法看起来像这样:
- (void) dealloc {
[[self wwanServiceId] release];
[super dealloc];
}
那么那里会发生什么?它将release
wwanServiceId
afaik,正如我所说,只有触及记忆管理的时间(如果我没有错过任何东西,但我觉得非常确定)是自动释放并保留它。
总结一下: 这里的想法是他认为,因为他在自动释放之后总是保留一份新副本,所以他最终需要释放它......或者这是我唯一能想到的东西。或者只是觉得最后做一个额外的释放是安全的,以防万一..?
因为据我所知,如果这个setter被调用一次,它将放置一个autorelease
(将来为-1),做一个retain
(+1)并且当调用析构函数时它会做“最终发布”(-1)。
任何有助于我理解的想法或建议(如果事实上我错了,内存处理是正确的)将不胜感激。
答案 0 :(得分:2)
您写道:
这里wwanServiceIdis是该类的NSString成员,对我而言,这似乎是一种奇怪的方式。据我所知,它会首先在对象上放一个自动释放,基本上说:“每当这个对象似乎不被使用时,为我释放它我并不在乎”然后副本将保留计数+1在.... wwanServiceId?还是newValue?我想是第一个。
这似乎指出了你的困惑的根源。 wwanServiceId
是变量,它可以包含对NSString
类型的对象的引用。变量没有只有对象的引用计数。
前一位员工写道:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
表达式[wwanServiceId autorelease]
表示:读取存储在wwanServiceId
中的引用并自动释放引用引用的对象 - 让我们调用该对象A. 重要:这不会删除对象A;它会在release
d之后的某个阶段,如果那时没有剩余的引用对象A将被删除。
表达式[newValue copy]
表示:读取存储在newValue
中的引用,用它来定位对象(称之为对象B),制作该对象的副本以生成新对象(称之为对象C),并返回对新对象的引用。这个新对象归copy
的调用者所有,因此无需retain
。
最后,赋值将对象C的引用存储到wwanServiceId
。
因此最多涉及三个不同的对象:
wwanServiceId
引用的原始对象,已自动释放,以删除wwanServiceId
的所有权。newValue
引用的对象,未触动wwanServiceId
为什么代码中的“autorelease”和上面的“最多三个不同”?
可以使用newValue
引用对象A来调用该方法,例如如:
[self setWwanServiceId:[self wwanServiceId]]
如果发生这种情况并且(a)使用release
而不是autorelease
而且(b)没有对对象A的其他引用,则release
将删除对象A和然后在评估[newValue copy]
时newValue
将引用已删除的对象...在这种情况下使用autorelease
会将删除延迟到复制之后。
所以前一位员工所写的并不是“错误的”,但正如其他一些答案所暗示的那样,这可能是一种不同寻常的风格。你看到这篇文章的另一种方式是:
- (void) setWwanServiceId: (NSString *) newValue
{
NSString *oldValue = wwanServiceId;
wwanServiceId = [newValue copy];
[oldValue release];
}
还确保在复制后发生任何删除。
HTH。
答案 1 :(得分:1)
简短而乐于助人:
这是错误的:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
这是对的:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
简而言之:
[wwanServiceId autorelease];
是一个不必要的已发送消息,因为自动释放对象将减少将来某个未知点的保留计数。在下一行中,您wwanServiceId = [newValue copy];
即刻设置实例变量。 所以,在你的记忆中你现在有一个自动释放的对象和一个新的对象。其中一个太多了新对象是你的IVar指针指向的地方。旧的游泳池在你的记忆池游泳,可能没有参考它: - )
尽可能少地自动释放或使用ARC。
哦:在dealloc
方法中,请不要发送这样的信息:
[[self wwanServiceId] release];
更像这样:
[wwanServiceId release];
因为Apple建议直接使用init
和dealloc
方法中的实例方法,而不是在那里使用getter和setter。
答案 2 :(得分:0)
调试它并查看。
[wwanServiceId autorelease];
wwanServiceId有一个地址。该声明不会改变它。它确实减少了该对象的保留计数。 而已。
wwanServiceId = [newValue copy];
此语句创建一个新对象。新对象是newValue的副本。比较对象的地址,你会看到,地址inn wwanServiceId将与newValue的地址不同,它将与wwanServiceId在执行语句之前所具有的地址不同。
copy
中隐含的保留将影响wwanServiceId,但它会影响新对象,该对象只是用copy
创建的。它不会影响在之前的语句中自动释放的wwanServiceId对象。
在执行setWwanServiceId
之后的某个时刻,旧的和自动释放的对象将消失。 (假设保留计数现在为0。如果它> 0,因为它仍然由于其他原因而保留或仅仅是因为错误,那么它将保留并可能导致泄漏。)
一旦你明白你将不再质疑dealloc方法中发生的事情。 wwanServiceId
已发布。意味着其保留计数减少1.如果它为0,则它将自动解除分配。
你甚至可以在那里自动发布它。自动释放的差异基本上是在执行当前方法时,自动释放的对象仍然存在且可用。它的发布将在稍后的某个时间点生效。
但是没有理由在dealloc中自动释放对象。
在给出的示例中,甚至没有充分的理由在setter setWwanServiceId
中自动释放对象。您可以直接在两种方法中释放对象。
答案 3 :(得分:0)
假设wwanServiceId
是由getter wwanServiceId
和setter setWwanServiceId
映射的私有ivar,我认为在setter中自动释放ivar是不正确的。
我会编写以下代码:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
我的意思是:没有必要将var的所有权授予自动释放池(它可能在应用程序结束时耗尽)。只需释放伊娃。如果有人使用它,没问题,它将有一个强烈的参考。否则它将被解除分配。