你知道哪些iPhone操作系统的内存管理规则和技巧?

5

目前,我正在涉足名为“iPhone OS中的内存管理”的冰冷水域。

这是我学到的一个规则:

每当我在我的方法中看到一个alloc时,我会在该方法底部释放相应的变量。

每当我在我的头文件中创建一个@ property(...),并且其中含有copy或retain关键字时,我会在dealloc方法中向该变量发送一条release消息。

每当我有一个IBOutlet时,我也会做同样的事情。唯一的例外是:如果IBOutlet具有类似@property(... assign)的内容,换句话说:如果它完全具有assign关键字。那么我不会在dealloc方法中释放它。

我觉得还有很多好的规则需要知道!只要写下你所拥有的东西。让我们把它们都集合起来。欢迎提供对其进行描述的优秀链接。


我也很感兴趣了解这些规则中哪些适用于 Cocoa(而非 Cocoa Touch),哪些应用方式不同。 - Debajit
4个回答

4

实际上,任何时候当你初始化一个对象并且方法名包含"init"时,你都需要负责释放它。如果你使用不包含单词"init"的Class方法创建对象,则不需要。

例如:

  NSString *person = [NSString stringWithFormat:"My name is %@", name];

不需要发布。但是:
  Person *person = [[Person alloc] init];

需要发布(如您在问题中所述)。同样地:
  Person *person = [[Person alloc] initWithName:@"Matt"]];

还需要发布。

这是一种惯例,而不是语言规则,但你会发现对于所有由苹果提供的API都是正确的。


你们两个都是对的,我在第三个例子中犯了一个很严重的打字错误。这就是我在网页浏览器中从记忆中输入的结果。我会进行修正。 - mmc
@mmc:第一个例子对于NSString *str = [NSString stringWithFormat:“My name is%@”,name];(如果我将其分配给NSString变量)也有效吗? - Thanks
是的,我很高兴我们思路一致。当你输入评论时,我编辑了第一个示例以使其更清晰 :)今天我的代码状态非常糟糕,甚至在工作中调试aspx错误页面...也许我今天不应该再回答任何问题 :) - mmc
虽然我对自己的知识还不确定(刚开始学习Objective-C和iPhone SDK),但我非常确定这些示例的正确性。我这里有一本大书,昨晚查了一下,也是这么说的。 - Thanks
不是这样的,初始化与此无关。应该写成,“每次调用alloc时,都需要考虑释放内存。” - rik.the.vik
显示剩余2条评论

4

我使用的规则

  • 释放所有使用以“alloc”或“new”开头或包含“copy”的方法创建的对象。

  • 释放所有保留的对象。

  • 不要释放使用+className方便构造函数创建的对象。(类创建它并负责释放它。)

  • 不要释放以其他方式接收到的对象。例如: mySprockets = [widget sprockets];

  • 如果您将接收到的对象存储在实例变量中,请保留它或复制它。(除非它是一个弱引用-只是指向另一个对象的指针,通常为了避免循环引用。)

  • 接收到的对象在它们接收到的方法中有效(一般情况下),如果传回给调用者,则也有效。

一些好的链接:

  1. http://www.gehacktes.net/2009/02/iphone-programming-part-2-objective-c-memory-management/
  2. http://mauvilasoftware.com/iphone_software_development/2008/01/iphone-memory-management-a-bri.html

2

当你看到每一行代码似乎都会出现segfaults(段错误)时,内存管理可能会让人感到令人生畏,但是一旦掌握了它的要领,实际上就非常容易。花点时间阅读这个页面,然后阅读苹果的文档,你应该很快就能写出无bug(错误)的代码。


1

我倾向于只创建自动释放的对象,无论是使用类方法还是在创建后立即进行自动释放,除非我有理由不这样做。例如:

  • 我将其分配给成员变量,因为我打算保留它一段时间。
  • 我只是创建它以立即传递给另一个方法,并在该方法调用之后立即发送释放消息。
  • 出于性能原因,我需要在最近的NSAutoreleasePool被释放之前释放该内存,例如在循环内创建大量对象或对象持有大量数据(例如图像)。

这样,我就不太可能泄漏对象。默认情况下,我会创建自动释放的对象,当我做出有意识的决定不对它们进行自动释放时,我会立即面临一个问题,即它们将在哪里被释放。

对于对象属性,我喜欢将它们赋值为nil,而不是在dealloc方法中释放它们。这样,保留或复制的属性会被发送释放消息,而分配的属性只是被覆盖,如果我将属性从保留更改为分配或反之亦然,我就不必更新dealloc方法。


1
在dealloc中赋值为nil(而不是调用release)是不被赞同的,因为如果另一个对象已经注册了KVO通知,或者您编写了一个尝试使用另一个实例变量(可能已经被清除)的自定义setter方法,那么可能会出现问题。 - Marc Charbonneau
我曾经这样做,但最终决定不再在自动释放池中拥有大量对象,因为这使得很难弄清楚发生了什么。现在我到处使用alloc/init和release,除非无法避免。 - Mark Bessey
@Marc:我没有考虑到这一点,感谢你指出来。我想这应该成为内存管理中的一个重点:避免在析构函数(dealloc方法)中产生副作用。 - Tony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接