iphone - 使用 Cocoa 和 Objective-C 理解引用计数

标签 iphone objective-c cocoa memory

我刚刚开始了解 Objective-C 和 Cocoa,以便使用 iPhone SDK。我对 C 的 mallocfree 概念相当满意,但 Cocoa 的引用计数方案让我很困惑。有人告诉我,一旦你理解它就非常优雅,但我还没有完成。

releaseretainautorelease 是如何工作的,它们的使用约定是什么?

(或者失败了,你读了什么帮助你得到它?)

最佳答案

让我们从retainrelease开始; autorelease 只是你了解基本概念后的一个特例。

在 Cocoa 中,每个对象都会跟踪它被引用的次数(具体来说,NSObject 基类实现了这一点)。通过在一个对象上调用 retain,你是在告诉它你想将它的引用计数加一。通过调用release,你告诉对象你正在释放它,并且它的引用计数被递减。如果在调用 release 后,引用计数现在为零,则系统会释放该对象的内存。

这与 mallocfree 的基本不同之处在于,任何给定对象都无需担心系统的其他部分崩溃,因为您已释放内存他们正在使用。假设每个人都在按照规则玩和保留/释放,当一段代码保留然后释放对象时,任何其他引用该对象的代码都不会受到影响。

有时令人困惑的是知道在什么情况下应该调用retainrelease。我的一般经验法则是,如果我想在某个对象上挂起一段时间(例如,如果它是类中的成员变量),那么我需要确保对象的引用计数知道我。如上所述,对象的引用计数通过调用 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/

相关文章:

ios - 为什么 "&", "+"字符没有在 iOS 中编码?

ios - 为 iPhone 和 iPad 制作一个 .IPA

ios - 使用 UIWebView 快速滚动

objective-c - 首字母缩略词的属性是否有任何 Objective-C/Cocoa 命名约定?

ios - UIbutton 的图像在 iOS 中被拉伸(stretch)

javascript - 在左上角制作一个重新加载按钮

ios - 如何创建动态 NSDictionary 来存储具有多个键的多个 URL?

ios - 使用 UIPageViewController 创建网格/ map

ios - 在 iOS 上保存 iCloud Drive 安全范围的 URL (UIDocumentPickerViewController)

multithreading - Mac OS 访问数据模型时是否会调用诸如drawRect : concurrently from different threads? 这样的显示方法,这不是很危险吗?