1. 底层机制
大家是否知道从旧时代的MRC到ARC机制到底意味着什么呢? 为什么ARC从开发速度,到执行速度和稳定性都要优于MRC?开发速度不言而喻,你少写很多release代码,甚至很少去操心这部分。执行速度呢?这个还要从runtime说起,还记得我在第2点说得一句话么:“Runtime is everything between your each function call.”
MRC是一个古老的内存管理哲学,谁分配谁释放。通过counting来计数到底该资源有几个使用者。道理很简单,但是往往简单的东西人却会犯错。从来没有一个程序员可以充满信心的说,我写得代码从来没有过内存泄露。这样来看,我们就更需要让程序可以自己处理这个管理机制,这就需要把这个机制放到runtime里。
所以MRC->ARC就是把内存管理部分从普通开发者的函数中移到了函数外的runtime中。因为runtime的开发原型简单,逻辑层次更高,所以做这个开发和管理出错的概率更小。实际上编译器开发人员对这部分经过无数次测试,所以可以说用ARC几乎不会出错。另外由于编译的额外优化,使得这个部分比程序员自己写得代码要快速很多。而且对于一些通用的开发模式,例如autorelease对象,ARC有更优秀的算法保证autoreleasepool里的对象更少。
2. RC规则
首先说一下RC是什么,r-Reference参照,引用 c-counting计数, RC就是引用计数。俗话说就是记录使用者的数量。 例如现在我有一个房间空着,大家可以进去随意使用,但是你进门前,需要给门口的计数牌子+1,
出门时候-1。 这时候这个门口的牌子就是该房间里的人数。一但这个牌子变为0我就可以把房间关闭。
这个规则可以让NSObject决定是不是要释放内存。当一个对象alloc时候,系统分配其一块内存并且object自动计数retainCount=1 这时候每当[object retain]一次retainCount+1(这里虽然简写也是rc不过是巧合或者当时开发人员故意选的retain这个词吧)每次[object release]时候retainCount-1 当retainCount==0时候object就真正把这快内存还给系统。
3. 常用container的Reference Counting特性
这个规则很简单把。但是这块确实让新手最头疼的地方。问题出在,新手总想去验证RC规则,又总是发现和自己的期望不符合。无数次看到有人写下如下句子
NSLog(@"%d",[object retainCount]);
while([object retainCount]>0){
[object release];
}
当然了,我也做过类似的动作,那种希望一切尽在掌握中的心态。但是你会看到其他人告诉这么做完全没有意义。rc does not work this way. 也许这样的暴力释放会起作用,但是retainCount并不是用来做这个的。每个数字意味着有其它对象引用该资源,这样的暴力释放很容易导致程序崩溃。这个数字也许并不是你心目中的哪个。因为你很难跟踪到底哪些对象引用的该资源。你用代码建立的资源不光只有你的代码才会用到,你调用的各种Framework,Framework调用的Framework,都有可能改变这个资源的retainCount.
所以去验证RC规则不是明智之举。你能做的就是理解规则,使用规则,读文档了解container的引用特性。或者干脆移到ARC上面,让runtime环境处理这些问题。最后说一下不用arc的情况。目前情况来看,有不少第三方的库并未支持ARC,所以如果你的旧项目使用了这些库,请检查是否作者发布了新版本,或者你需要自己修正支持ARC。
最后补充记录下ARC的新规则(ARC Enforces New Rules):
为了正常运转,ARC使用了一些在使用其它编译模式下没有的新规则。这些规则意在提供完全可靠的内存管理模型;在某些情况下,它们仅使用最佳实践方法,在其它情况下,它们仅简化你的代码或明显的做出推论告知你不需要处理内存管理。如果你违反了这些规则,你会马上得到一个编译期错误,而不是在运行期可能会显现的一个狡猾的bug。
1.不能显示的调用dealloc,实现或调用 retain, release, retainCount,或 autorelease。
同样也不要能使用 @selector(retain), @selector(release), 等等类似的选择器。
如果你需要管理资源而不是释放实例变量,那你可以实现 dealloc方法。你不需要(事实上你不能)释放实例变量,但你可能需要在系统类和其它的未使用ARC代码中调用 [systemClassInstance setDelegate:nil] 方法。
在ARC中自定义的 dealloc方法不要调用 [super dealloc]方法(它实际上会导致编译器错误)。到super的链式调用是自动的并且是编译器强制执行的。你仍可以在Core Foundation样式的的对象上,使用CFRetain, CFRelease,和其它相关的函数。
2.你不能使用 NSAllocateObject 或 NSDeallocateObject
你使用 alloc来创建对象;运行时系统会注意释放这些对象。
3.你不能在C语言结构体中使用对象指针。 与其使用一个结构体( struct),不如创建一个Objective-C类来管理数据。
4. id与 void*之间不能随意转换
你必须使用特定的类型转换来告诉编译器对象的生命周期。你需要在Objective-C对象和以函数参数传入的Core Foundation类型值之间进行这样的转换。有关详情,参见“Managing Toll-Free Bridging”。
5.你不能使用 NSAutoreleasePool对象
ARC 提供了 @autoreleasepool来代替。这比 NSAutoreleasePool更高效。
6.你不能使用内存区(memory zones)。
再也没有使用 NSZone的必要了——现代的Obj-C运行时会永远忽略它。
为了允许与自动retain-release的代码进行交互,ARC在方法命名上加上了一个约束:
你不能以 new为开头命名一个访问器的名字。这反过来意味着你不必声明一个以new开头的属性,除非你指定一个不同名称的getter方法: