Dav*_*vid 3 cocoa memory-management objective-c
我正在尝试学习/了解在使用或创建各种对象时会发生什么以及为什么.(希望从文档中学习.)
我正在阅读"Objective-C 2.0编程"(Steven Kochan的第2版).在页408,第一段是保留计数的讨论:
请注意,它的引用计数然后转到2.该
addObject:方法自动执行此操作; 如果你检查你的文档的addObject:方法,你会看到这里描述的事实.
所以我读了addObject:文档:
在数组末尾插入给定对象.
在那里,缺少描述,而其他项目,如arrayByAddingObject:,声明:
返回一个新数组,该数组是接收数组的副本,并将给定对象添加到结尾.
在参考文献中它表明addObject:增加保留计数?鉴于ARC的存在,我仍然应该了解这些方法正在做些什么来避免错误和问题.ARC为此带来了什么?(再读一遍......)
很棒的问题,我很高兴看到有人真正阅读文档并试图理解它们!
既然您正在寻找如何使用Apple的文档来研究答案,而不是实际答案本身,那么我就是这样找到答案的:
addObject:它是一种方法,NSMutableArray并没有提到内存管理.NSArray是最直接的父级.我们来看看:特别注意事项
在大多数情况下,您的自定义NSArray类应符合Cocoa的对象所有权约定.因此,您必须将retain添加到您添加到集合中的每个对象,并释放到从集合中删除的每个对象.当然,如果继承NSArray的原因是为了实现与规范不同的对象保留行为(例如,非保留数组),那么您可以忽略此要求.
NSArray是NSObject,我知道在这种情况下它不会被覆盖(来自经验),所以我不打算检查它.(如果父母是另一个类或可能被NSObject覆盖的东西,我会继续向上移动树,直到我找到了什么.) 当您将对象添加到NSMutableArray对象时,不会复制该对象(除非您将YES作为参数传递给initWithArray:copyItems :).而是将对象直接添加到数组中.在托管内存环境中,对象在添加时会收到保留消息; 在垃圾收集环境中,它被强烈引用.在托管内存环境中取消分配数组时,会向每个元素发送一条释放消息.有关复制和内存管理的详细信息,请参阅"复制集合".
这本书必须提到过时的文档,因为你是正确的,它没有提到有关保留计数的任何内容.事实上它确实保留了对象.你需要考虑它的方式不是保留计数(这是无用的)而是所有权.特别是在使用ARC时.
当您向对象添加对象时NSMutableArray,它将获取该对象的所有权(在ARC术语中,它具有对它的强引用).
"ARC为此带来了什么?"
ARC没有什么不同.所有ARC(除了一些优化之外)都会添加相同的release,retain和autorelease语句,您可以在不使用ARC的情况下自行添加.您需要关心的是,一旦将对象添加到数组中,它将至少与数组一样长.
并且该arrayByAddingObject:方法创建一个包含您传递的对象的新NSArray(或NSMutableArray),并保持对传递的对象的强引用.除非您将其分配给ivar,property或local变量,否则它创建的实际数组对象尚未引用.您分配的内容决定了它的使用寿命.
基本上即使没有ARC,最好根据所有权来考虑对象生命周期,ARC只是将其正式化.因此,在使用框架时,保留发生或不发生并不重要,在将所有权传递给另一个对象之前,您只负责对象,并且您可以相信框架将使对象保持活动状态只要它需要它.
当然,你必须知道什么是所有权.例如委托特性通常assign,或者在ARC unsafe_unretained或weak,为防止圆形保持周期(其中,每个的两个对象保持彼此),虽然有时保留/强,所以你需要逐个寻找到那些上的情况.
而且在键值观察和NSNotification等情况下,观察您观察的对象并不会保留观察者.
但这些确实是规则的例外.通常,您可以假设一个强大的参考.
关于上面这句话:"它创建的实际数组对象还没有引用,除非你将它分配给ivar,property或local变量.你赋予它的确定它的生命周期." 我会试着解释一下:
当你运行这段代码:[someArray arrayByAddingObject:someObject];你实例化一个新的NSArray或NSMutableArray对象(取决于对象类型someArray的),但你没有实际它分配给任何引用.这意味着如果您使用ARC,它可能会在之后立即释放,或者如果不使用ARC,它将在autoreleasepool耗尽时释放(可能在该线程的runloop的下一次迭代中).
现在,如果你这样做了:NSArray *someOtherArray = [someArray arrayByAddingObject:someObject];你现在有了一个名为someOtherArray的新创建的数组的引用.在这种情况下,这是一个局部变量,其范围仅在{ }它所驻留的任何一个范围内(因此它可以在一个if语句,一个循环或一个方法中.现在如果你什么也不做,它会在它之后的某个时候死掉)范围结束(不保证立即死亡,但这并不重要,你不能认为它的寿命更长).
现在,如果你的类中有一个iVar(实例变量)在标题中声明NSArray *someOtherArray;(在ARC中默认为强)并且你someOtherArray = [someArray arrayByAddingObject:someObject];在类中的某个地方运行,该对象将一直存在,直到你删除引用(someOtherArray = nil),你覆盖引用(someOtherArray = someThirdArray)或类已取消分配.如果你不使用ARC,你必须确保保留它以达到相同的效果(someOtherArray = [[someArray arrayByAddingObject:someObject] retain];这实际上是ARC在幕后所做的).
或者你可能有一个声明的属性,比如@property (nonatomic, strong) NSArray *someOtherArray在其中self.someOtherArray = [someArray arrayByAddingObject:someObject];可以达到相同的效果但是会使用proprety accessor(setSomeOtherArray:),或者你仍然可以someOtherArray = [someArray arrayByAddingObject:someObject];用来直接设置iVar(假设你@synthesized).
或取非ARC,你可能宣布类似的财产@property (nonatomic, retain) NSArray *someOtherArray中self.someOtherArray = [someArray arrayByAddingObject:someObject];会表现得完全一样ARC会,但设置伊娃时,直接你仍然需要添加手动保留.
我希望稍微澄清一下,如果有任何我掩饰或遗漏的东西,请告诉我.
正如您在评论中提到的,这里的关键是直观地知道对象何时被另一个对象视为拥有.幸运的是,Cocoa框架遵循一套非常严格的约定,允许您做出安全的假设:
NSString框架对象的text属性(UILabel例如,例如属性)时,它总是被复制(如果有人知道反例,请注释或编辑).因此,一旦传递它,您就不必担心它的字符串.复制字符串以防止可变字符串在传递后被更改.delegate,它(几乎?)始终保留(或ARC中的强引用)a有一个b强引用的属性,并且b具有强引用的委托属性.您设置a为委托b.现在a并且b两者都强烈引用彼此,并且任何对象都不会达到保留计数0并且永远不会达到它的dealloc方法来释放另一个对象.NSURLConnection是一个反例,它强烈引用它的委托,因为它的委托是通过一个方法设置的 - 参见下面的约定 - 并且它的约定是NSURLConnection在它完成后nil out或release a 而不是in dealloc,这将取消通函保留)NSURLConnection甚至保留它的委托,因为它是通过方法传入的,而当设置其他对象的委托属性时将不会保留,因为这是约定.建议您在自己的类中遵循这些相同的约定以保持一致性.
另外,不要忘记所有类的标题都可供您使用,因此您可以轻松查看属性是保留还是分配(或强或弱).您无法检查哪些方法对其参数有效,但由于参数由接收方拥有,因此不需要.
通常,您应该在"最全局"的位置查看有关Cocoa API中任何内容的信息.由于内存管理在整个系统API中普遍存在,并且 API在Cocoa内存管理策略的实现中是一致的,因此您只需阅读并理解Cocoa内存管理指南.
一旦理解,您可以安全地假设所有系统API都实现了该内存管理策略,除非另有明确说明.
因此,对于NSMutableArray的addObject:方法,它必须 retain将对象添加到数组中,否则它将违反该标准策略.
你会在整个文档中看到这一点.这可以防止每个方法的文档都是一个页面或更长的时间,并且当罕见的方法或类实现某些东西时,这是显而易见的,无论出于何种原因(有时不太好),该规则都是例外.
在内存管理指南的"基本内存管理规则"部分中:
您可以使用retain获取对象的所有权.
通常保证接收到的对象在接收到的方法中保持有效,并且该方法也可以安全地将对象返回给其调用者.在两种情况下使用retain:(1)在accessor方法或init方法的实现中,获取要存储为对象属性的对象的所有权; (2)防止对象因某些其他操作的副作用而失效(如"避免导致重新分配您正在使用的对象"中所述).
(2)是关键; NS {Mutable}数组必须retain完全添加任何对象,因为它需要防止添加的对象因某些副作用而失效.不这样做将与上述规则不同,因此,将明确记录.
| 归档时间: |
|
| 查看次数: |
268 次 |
| 最近记录: |