Iphone 为什么自实现的getter应该保留并自动释放返回的对象?

Iphone 为什么自实现的getter应该保留并自动释放返回的对象?,iphone,cocoa-touch,memory-management,uikit,Iphone,Cocoa Touch,Memory Management,Uikit,例如: - (NSString*) title { return [[title retain] autorelease]; } 二传手实际上已经保留了它,对吗?事实上,任何人都不应该绕过二传手。。。所以我想知道为什么getter不只是返回对象?它实际上已经被保留了。或者,如果同时另一个对象被传递给setter,是否需要这样做? 或 有什么区别? 第二种方法允许调用方获取容器对象的实例变量,处置容器并继续使用实例变量,直到当前自动释放池的下一个版本,而不会因释放其容器间接生成的实例变量

例如:

- (NSString*) title {
    return [[title retain] autorelease];
}
二传手实际上已经保留了它,对吗?事实上,任何人都不应该绕过二传手。。。所以我想知道为什么getter不只是返回对象?它实际上已经被保留了。或者,如果同时另一个对象被传递给setter,是否需要这样做?

有什么区别? 第二种方法允许调用方获取容器对象的实例变量,处置容器并继续使用实例变量,直到当前自动释放池的下一个版本,而不会因释放其容器间接生成的实例变量而受到伤害:

aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
如果“get”是在第一种形式中实现的,您应该写:

aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
就代码执行速度而言,第一种形式更有效一些。 但是,如果你正在编写供他人使用的框架,也许应该推荐第二个版本:它使使用你的框架的人的生活变得更轻松:他们不必过多地考虑他们正在做什么……;)
如果您选择第一个样式版本,请在文档中明确说明……无论您选择何种方式,请记住,从版本1更改为版本2是为客户机代码保存的,当从版本2返回到版本1时,将破坏现有的客户机代码……

我以前从未见过这种模式,但这对我来说似乎毫无意义。我想这样做的目的是在客户端代码调用父对象上的“release”时,确保返回值的安全。这并没有真正伤害到任何东西,但我怀疑这种情况在精心设计的库中经常出现


啊,好的。从smorgan链接的文档来看,这似乎是苹果目前推荐人们使用的方法之一。我想我还是更喜欢老派的版本:

- (NSString *) value
{
    return myValue;
}

- (void) setValue: (NSString *) newValue
{
    if (newValue != myValue)
    {
       [myValue autorelease]; // actually, I nearly always use 'release' here
       myValue = [newValue retain];
    }
}

这不仅仅适用于有人释放容器的情况,因为在这种情况下,更明显的是他们应该自己保留对象。考虑这个代码:

NSString* newValue = @"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
这看起来很合理,但是如果setter和getter都不使用autorelease,“继续做某事”部分可能会崩溃,因为oldValue现在已经被释放(假设没有其他人保留它)。您通常希望从中使用技巧1或技巧2,以便像上面这样的代码可以像大多数人期望的那样工作。

比较此代码

  return [[title retain] release]; // releases immediately
用这个

  return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
第二种方法保证客户端将有一个未解除分配的对象来处理

在这样的情况下(客户机代码):

title
方法中保留(并使用
autorelease
而不是
release
)可防止此代码爆炸。
在执行完当前调用堆栈(当前运行循环结束)之前,自动释放对象不会调用其
release
方法。这使调用堆栈中的所有客户端代码都有机会使用此对象,而不用担心它会被释放


需要记住的重要一点是:这不是Java、Ruby或PHP。仅仅因为您在yer[sic]变量中有一个对对象的引用,并不能确保您不会将其从您的下方解除锁定。您必须保留它,但是然后您必须记住释放它。自动释放可以避免这种情况。除非您处理的是多次迭代的属性或循环,否则您应该始终使用自动释放(除非出现问题,否则可能不会)。例如,这是对可以从多个线程访问的属性的绝对要求。更一般地说,不经常出现的情况会导致非常恼人的头痛。我想我明白你的意思,关于多线程,因为你可以有多个独立的发布池和运行循环。我仍然认为setter中的自动释放在这种情况下更有意义。在多线程访问的情况下,我通常使用[obj copy]——拥有单独的对象实例可以消除任何冲突的机会。如果使用
[obj copy]
,那么您在发送回的obj上有一个额外的保留。谁将发布它?因此,您最终执行的是相同的
[[obj copy]自动释放]
。只需返回
myValue
(旧式版本)在没有安全之前是安全的,就像海平面发电机一样。另请参见我的问题:
  return [[title retain] release]; // releases immediately
  return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
 NSString *thing = [obj title];
 [obj setTitle:nil]; // here you could hit retainCount 0!
 NSLog(@"Length %d", [thing length]); // here thing might be dealloced already!