作者:故事与酒 | 来源:互联网 | 2023-07-14 23:59
什么是ARCAutomaticReferenceCounting,自动引用计数,即ARC,可以说是WWDC2011和iOS5所引入的最大的变革和最激动人心的变化。ARC是新的L
>什么是ARC
>Automatic Reference
Counting,自动引用计数,即ARC,可以说是WWDC2011和iOS5所引入的最大的变革和最激动人心的变化。ARC是新的LLVM 3.0编译器的一项特性,使用ARC,可以说一举解决了广大iOS开发者所憎恨的手动内存管理的麻烦。
>在工程中使用ARC非常简单:只需要像往常那样编写代码,只不过永远不写retain,release和autorelease三个关键字就好~这是ARC的基本原则。当ARC开启时,编译器将自动在代码合适的地方插入retain,
release和autorelease,而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用ARC了)。好了,ARC相当简单吧~到此为止,本教程结束。
>等等…也许还有其他问题,最严重的问题是“我怎么确定让ARC来管理不会出问题?”或者“用ARC会让程序性能下降吧”。对于ARC不能正处理内存管理的质疑自从ARC出生以来就一直存在,而现在越来越多的代码转向ARC并取得了很好的效果,这证明了ARC是一套有效的简化开发复杂程度的机制,另外通过研究ARC的原理,可以知道使用ARC甚至能提高程序的效率。在接下来将详细解释ARC的运行机理并且提供了一个step-by-step的教程,将非ARC的程序转换为ARC。
>ARC工作原理
>手动内存管理的机理大家应该已经非常清楚了,简单来说,只要遵循以下三点就可以在手动内存管理中避免绝大部分的麻烦:
>如果需要持有一个对象,那么对其发送retain
如果之后不再使用该对象,那么需要对其发送release(或者autorealse)
每一次对retain,alloc或者new的调用,需要对应一次release或autorealse调用
>初学者可能仅仅只是知道这些规则,但是在实际使用时难免犯错。但是当开发者经常使用手动引用计数 Manual
Referecen
Counting(MRC)的话,这些规则将逐渐变为本能。你会发现少一个release的代码怎么看怎么别扭,从而减少或者杜绝内存管理的错误。可以说MRC的规则非常简单,但是同时也非常容易出错。往往很小的错误就将引起crash或者OOM之类的严重问题。
>在MRC的年代里,为了避免不小心忘写release,Xcode提供了一个很实用的小工具来帮助可能存在的代码问题(Xcode3里默认快捷键Shift+A?不记得了),可以指出潜在的内存泄露或者过多释放。而ARC在此基础上更进一步:ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做的只不过是在代码编译时为你自动在合适的位置插入release或autorelease,就如同之前MRC时你所做的那样。因此,至少在效率上ARC机制是不会比MRC弱的,而因为可以在最合适的地方完成引用计数的维护,以及部分优化,使用ARC甚至能比MRC取得更高的运行效率。
>ARC机制
>学习ARC很简单,在MRC时代你需要自己retain一个想要保持的对象,而现在不需要了。现在唯一要做的是用一个指针指向这个对象,只要指针没有被置空,对象就会一直保持在堆上。当将指针指向新值时,原来的对象会被release一次。这对实例变量,sunthesize的变量或者局部变量都是适用的。比如
- NSString *firstName =
self.textField.text;
>firstName现在指向NSString对象,这时这个对象(textField的内容字符串)将被hold住。比如用字符串@“OneV”作为例子,这个时候firstName持有了@”OneV”。
>alt="211507693.png" src="https://img.php1.cn/3cd4a/1eebe/cd5/bff2716168d1ed7b.webp" alt="211538170.png" src="https://img.php1.cn/3cd4a/1eebe/cd5/eec57030b649a106.webp"
alt="211605437.png" src="https://img.php1.cn/3cd4a/1eebe/cd5/e3aa5425383ba10d.png"
alt="211630454.png" src="https://img.php1.cn/3cd4a/1eebe/cd5/21e585a7e21fc7dc.png"
alt="211656973.png" src="https://img.php1.cn/3cd4a/1eebe/cd5/0d80e8a685a9a87b.png"
alt="211721950.png" src="https://img.php1.cn/3cd4a/18ace/696/1d8e759bd3e6bbec.jpeg"
alt="211745323.png" src="http://bbs.9ria.com/forum.php?mod=attachment&aid=MTI2NTMzfDFlN2IwMTEzfDEzOTI4MjcyNDZ8MHwxOTc4NTI%3D&noupdate=yes"
>
>注意类似下面的代码似乎是没有什么意义的:
- __weak NSString *str = [[NSString alloc] initWithFormat:…];
- NSLog(@"%@",str); //输出是"(null)"
>由于str是weak,它不会持有alloc出来的NSString对象,因此这个对象由于没有有效的strong指针指向,所以在生成的同时就被销毁了。如果我们在Xcode中写了上面的代码,我们应该会得到一个警告,因为无论何时这种情况似乎都是不太可能出现的。你可以把weak换成strong来消除警告,或者直接前面什么都不写,因为ARC中默认的指针类型就是strong。
>property也可以用strong或weak来标记,简单地把原来写retain和assign的地方替换成strong或者weak就可以了。
- @property (nonatomic, strong) NSString *firstName;
- @property (nonatomic, weak) id
delegate;
>ARC可以为开发者节省很多代码,使用ARC以后再也不需要关心什么时候retain,什么时候release,但是这并不意味你可以不思考内存管理,你可能需要经常性地问自己这个问题:谁持有这个对象?
>比如下面的代码,假设array是一个NSMutableArray并且里面至少有一个对象:
- id obj = [array objectAtIndex:0];
- [array removeObjectAtIndex:0];
- NSLog(@"%@",obj);
>在MRC时代这几行代码应该就挂掉了,因为array中0号对象被remove以后就被立即销毁了,因此obj指向了一个dealloced的对象,因此在NSLog的时候将出现EXC_BAD_ACCESS。而在ARC中由于obj是strong的,因此它持有了array中的首个对象,array不再是该对象的唯一持有者。即使我们从array中将obj移除了,它也依然被别的指针持有,因此不会被销毁。
>一点提醒
>ARC也有一些缺点,对于初学者来说,可能仅只能将ARC用在objective-c对象上(也即继承自NSObject的对象),但是如果涉及到较为底层的东西,比如Core
Foundation中的malloc()或者free()等,ARC就鞭长莫及了,这时候还是需要自己手动进行内存管理。在之后我们会看到一些这方面的例子。另外为了确保ARC能正确的工作,有些语法规则也会因为ARC而变得稍微严格一些。
>ARC确实可以在适当的地方为代码添加retain或者release,但是这并不意味着你可以完全忘记内存管理,因为你必须在合适的地方把strong指针手动设置到nil,否则app很可能会oom。简单说还是那句话,你必须时刻清醒谁持有了哪些对象,而这些持有者在什么时候应该变为指向nil。
>ARC必然是Objective-C以及Apple开发的趋势,今后也会有越来越多的项目采用ARC(甚至不排除MRC在未来某个版本被弃用的可能),>Apple也一直鼓励开发者开始使用ARC,因为它确实可以简化代码并增强其稳定性。可以这么说,使用ARC之后,由于内存问题造成的crash基本就是过去式了(OOM除外
)
>我们正处于由MRC向ARC转变的节点上,因此可能有时候我们需要在ARC和MRC的代码间来回切换和适配。Apple也想到了这一点,因此为开发这提供了一些ARC和非ARC代码混编的机制,这些也将在之后的例子中列出。另外ARC甚至可以用在C++的代码中,而通过遵守一些代码规则,iOS
4里也可以使用ARC(虽然我个人认为在现在iOS 6都呼之欲出的年代已经基本没有需要为iOS 4做适配的必要了)、
>总之,聪明的开发者总会尝试尽可能的自动化流程,已减轻自己的工作负担,而ARC恰恰就为我们提供了这样的好处:自动帮我们完成了很多以前需要手动完成的工作,因此对我来说,转向ARC是一件不需要考虑的事情。