1.什么是ARC
ARC(automatic reference counting ),自动引用计数,iOS5之后引入的。是新的LLVM3.0的新特性。简单地说,在工程中使用arc,你可以正常编写代码,只是不手动添加retain,release和autorelease关键字(这是arc的基本原则)来管理内存,因为当你开启arc时,编译器会自动在合适的地方插入retain,release以及autorelease.
ARC简化引用计数,自动管理引用计数 。引用计数机制通过可以递增递减的计数器来管理内存。 在引用计数架构下,对象有个计数器,用以表示当前有多少个事物想令此对象存活下去,对象创建出来时,其保留计数至少为1。如果想令其继续存活,就retain它,不再使用此对象时就release或autorelease它。最终对象的引用计数为0时,对象会被deallocated。不过使用 ARC简化引用计数后,上面那些对对象引用计数的管理就由编译器帮你处理。
2.使用ARC必须遵循的方法命名规则
若方法名以以下词语开头,返回的对象归调用者所有
(1)alloc
(2)new
(3)copy
(4)mutableCopy
归调用者所有表示的是调用以上词语开头的方法的代码要负责释放方法所返回的对象,即如返回对象的保留计数为正值,则代码要负责抵消一次计数值。
3.ARC工作原理
1)strong(retain)
对于mac,需要自己retain一个想要保持的对象,但是对于arc,只需要用一个指针指向这个对象,只要指针未被置空,对象会一直保持在堆上。当指针指向新值时,原来的对象会被release一次。适用于实例变量,synthesize的变量或者局部变量。
例如:NSString *firstName=self.textField.text;
firstName现在指向NSString 对象,这时这个NSString 对象(textField的内容字符串)将被hold住。比如用字符串@“OneV”为例(虽然实际上不应该用字符串举例子,因为字符串的retainCount规则其实和普通的对象不一样,大家就把它当作一个普通的对象来看吧…),这时firstName持有了@“OneV”。
一个对象拥有多个持有者(类似mrc中tetaincount>1)。此例中self.textField.text也持有@“OneV",即两个指针指向@“OneV"对象。如图。
如果textField中输入了其他东西,则self.textField.text指针指向其他内容,比如@“onevcat”,此时持有关系如图。
如果 firstName也设定新值,或超出作用范围的空间(比如它是局部变量但是这个方法执行完了或者它是实例变量但是这个实例被销毁了),那么此时firstName也不再持有@“OneV”,此时没有指针指向@“OneV”,故在arc中,将@“OneV”销毁,内存释放。
综上,类似firstName和self.textField.text这样的指针使用关键字strong进行标志,它意味着只要该指针指向某个对象,那么这个对象就不会被销毁。即arc的一个基本规则是只要某个对象被任一strong指针指向,那它将不会被销毁。如果对象没有被任何strong指针指向,那么就会被销毁。默认情况下,所有的实例变量和局部变量都是strong类型的(可以说strong类型的指针在行为上和MRC时代retain的property是比较相似的。)
2)weak
weak类型的指针可以指向对象但不会持有对象。比如
__weak NSString *weakName = self.textField.text的指向关系是
这里声明了一个weak的指针weakName,它并不持有@“onevcat”。如果self.textField.text的内容发生改变的话,根据之前提到的”只要某个对象被任一strong指针指向,那么它将不会被销毁。如果对象没有被任何strong指针指向,那么就将被销毁”原则,此时指向@“onevcat”的指针中没有strong类型的指针,@”onevcat”将被销毁。同时,在ARC机制作用下,所有指向这个对象的weak指针将被置为nil。这个特性相当有用,相信无数的开发者都曾经被指针指向已释放对象所造成的EXC_BAD_ACCESS困扰过,使用ARC以后,不论是strong还是weak类型的指针,都不再会指向一个dealloced的对象,从根源上解决了意外释放导致的crash。
不过在大部分情况下,weak类型的指针可能并不会很常用。比较常见的用法是在两个对象间存在包含关系时:对象1有一个strong指针指向对象2,并持有它,而对象2中只有一个weak指针指回对象1,从而避免了循环持有。一个常见的例子就是oc中常见的delegate设计模式,viewController中有一个strong指针指向它所负责管理的UITableView,而UITableView中的dataSource和delegate指针都是指向viewController的weak指针。可以说,weak指针的行为和MRC时代的assign有一些相似点,但是考虑到weak指针更聪明些(会自动指向nil),因此还是有所不同的。细节的东西我们稍后再说。
提醒
注意类似下面的代码似乎是没有什么意义的:
__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移除了,它也依然被别的指针持有,因此不会被销毁。
参考文章出处:http://www.onevcat.com/2012/06/arc-hand-by-hand/