我刚刚开始了解 Objective-C 和 Cocoa,以便使用 iPhone SDK。我对 C 的 malloc
和 free
概念相当满意,但 Cocoa 的引用计数方案让我很困惑。有人告诉我,一旦你理解它就非常优雅,但我还没有完成。
release
、retain
和 autorelease
是如何工作的,它们的使用约定是什么?
(或者失败了,你读了什么帮助你得到它?)
最佳答案
让我们从retain
和release
开始; autorelease
只是你了解基本概念后的一个特例。
在 Cocoa 中,每个对象都会跟踪它被引用的次数(具体来说,NSObject
基类实现了这一点)。通过在一个对象上调用 retain
,你是在告诉它你想将它的引用计数加一。通过调用release
,你告诉对象你正在释放它,并且它的引用计数被递减。如果在调用 release
后,引用计数现在为零,则系统会释放该对象的内存。
这与 malloc
和 free
的基本不同之处在于,任何给定对象都无需担心系统的其他部分崩溃,因为您已释放内存他们正在使用。假设每个人都在按照规则玩和保留/释放,当一段代码保留然后释放对象时,任何其他引用该对象的代码都不会受到影响。
有时令人困惑的是知道在什么情况下应该调用retain
和release
。我的一般经验法则是,如果我想在某个对象上挂起一段时间(例如,如果它是类中的成员变量),那么我需要确保对象的引用计数知道我。如上所述,对象的引用计数通过调用 retain
递增。按照惯例,当使用“init”方法创建对象时,它也会增加(实际上设置为 1)。在这两种情况下,我有责任在完成对象后调用 release
。如果我不这样做,就会出现内存泄漏。
对象创建示例:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
现在是 autorelease
。自动释放被用作一种方便(有时是必要的)方法来告诉系统在一段时间后释放这个对象。从管道的角度来看,当调用 autorelease
时,当前线程的 NSAutoreleasePool
会收到调用警报。 NSAutoreleasePool
现在知道一旦它获得机会(在事件循环的当前迭代之后),它可以在对象上调用 release
。从我们作为程序员的角度来看,它负责为我们调用 release
,所以我们不必(事实上,我们不应该)。
需要注意的重要一点是(同样,按照惯例)所有对象创建 class 方法都会返回一个自动释放的对象。例如,在下面的例子中,变量“s”的引用计数为 1,但在事件循环完成后,它将被销毁。
NSString* s = [NSString stringWithString:@"Hello World"];
如果你想卡在那个字符串上,你需要显式调用 retain
,然后在完成后显式调用 release
。
考虑以下(非常做作的)代码,您会看到需要 autorelease
的情况:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
我意识到这一切有点令人困惑——不过,在某些时候,它会点击。这里有一些引用资料可以帮助您:
- Apple's introduction到内存管理。
- Cocoa Programming for Mac OS X (4th Edition) , 亚伦·希勒加斯 (Aaron Hillegas) 着——一本写得很好的书,里面有很多很好的例子。读起来像教程。
- 如果您真的想深入了解,可以前往 Big Nerd Ranch .这是由上述书籍的作者 Aaron Hillegas 经营的培训机构。几年前我参加了 cocoa 介绍类(class),这是一种很好的学习方式。
关于iphone - 使用 Cocoa 和 Objective-C 理解引用计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6578/