我刚刚开始了解Objective-C和Cocoa,以期使用iPhone SDK.我对C的mallocfree概念相当满意,但Cocoa的参考计数方案让我相当困惑.有人告诉我,一旦你理解了它,它就非常优雅了,但我只是还没有走出低谷.

releaseretainautorelease是如何工作的?它们的使用有哪些约定?

(或者,如果没有做到这一点,你读了什么帮助你得到了它?)

推荐答案

让我们从retainrelease开始;一旦你理解了基本概念,autorelease实际上只是一个特例.

在Cocoa中,每个对象都跟踪它被引用的次数(具体来说,NSObject基类实现了这一点).通过对一个对象调用retain,您告诉它您想将其引用计数增加1.通过拨打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.自动释放被用作一种方便(有时是必要的)方式,告诉系统在一段时间后释放此对象.从管道Angular 来看,当调用autorelease时,当前线程的NSAutoreleasePool将收到调用的alert .NSAutoreleasePool现在知道,一旦获得机会(在事件循环的当前迭代之后),它就可以对对象调用release.从我们作为程序员的Angular 来看,它负责为我们拨打release,所以我们不必(事实上,我们不应该).

需要注意的是(按照惯例),所有对象创建方法都会返回一个自动删除的对象.例如,在下面的示例中,变量"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 to memory management.
  • Cocoa Programming for Mac OS X (4th Edition), by Aaron Hillegas - a very well written book with lots of great examples. It reads like a tutorial.
  • 如果你真的投入,你可能会达到Big Nerd Ranch.这是一个由亚伦·希尔莱加斯经营的训练设施,他是上述书的作者.几年前,我在那里参加了可可介绍课程,这是一个很好的学习方式.

Objective-c相关问答推荐

CLLocationManager startUpdatingLocation 未调用 locationManager:didUpdateLocations: 或 locationManager:didFailWithError:

iOS9 - 这个应用程序正在从后台线程修改自动布局引擎 - 在哪里?

XCTAssertEqual 错误:(3)不等于(3)

NSError 和 __autoreleasing

使用 ARC,什么更好:alloc 或 autorelease 初始化程序?

如果用户点击屏幕键盘,我如何关闭键盘?

#if 和 #ifdef Objective-C 预处理器宏有什么区别?

碰撞技术如何运作?

更改 UIDatePicker 字体 colored颜色 ?

捕获组在 NSRegularExpression 中不起作用

用于 iOS 开发的 LLVM 与 GCC

xcode storyboard Container View - 如何访问视图控制器

如何从 CGPoint 和 CGSize 创建 CGRect?

在 ios8 中没有调用 didRegisterForRemoteNotificationsWithDeviceToken,但是 didRegister...Settings 是

如何确定 UICollectionView flowLayout 中单元格之间的间距

NS_ASSUME_NONNULL_BEGIN 宏

UITableView ,重新加载时滚动到底部?

为什么 Select Emacs/Vim/Textmate? Xcode 还不够好吗?

字符串常量和字符串文字有什么区别?

如何在 iPhone SDK 中包含和使用新字体?