简介
ARC是编译器特性,而不是iOS运行时特性(除了weak指针系统)【ARC和手动内存管理性能是一样的,有些时候还能更加快速,因为编译器还可以执行某些优化】
指针保持对象的生命
ARC的规则非常简单:只要还有一个变量指向对象,对象就会保持在内存中。(当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放)
我们可以按“所有权”(ownership)来考虑ARC对象,一个对象可以有多个拥有者。只有当对象一个拥有者也没有的情况下才被释放。而能够作为对象拥有者的指针为“strong”,默认的实例变量和本地变量都是strong类型的指针。
另外还有一种“weak”指针,weak变量仍然指向一个对象,但不是对象的拥有者;当weak指向的变量的拥有者不再拥有时,变量被释放,此时weak变量会自动变为nil,称为“zeroing weak pointer”,这样阻止了weak指针继续指向已释放的对象。
weak指针主要用于“父-子”关系,父亲拥有一个儿子的strong指针,因此是儿子的所有者;但为了阻止所有权回环,儿子需要使用weak指针指向父亲,典型例子是delegate模式
id obj = [array objectAtIndex:0];[array removeObjectAtIndex:0];NSLog(@"%@",obj);
在ARC中这段代码是完全合法的。
ARC的限制
ARC只能工作与Objective-C对象,如果应用使用了Core Foundation 或malloc()/free(),此时需要你来管理内存。因为strong指针会保持对象的生命,某些情况下你仍然需要手动设置这些指针为nil,无论你何时创建了一个新对象时,都需要考虑谁拥有该对象,以及这个对象需要存活多久。
XCode 的ARC迁移
ARC是LLVM3.0编译器的特性,而现有工程可能使用老的GCC4.2或LLVM-GCC编译器,因此需要首先设置使用LLVM3.0编译器
Project Settings -> target -> Build Settings 搜索compiler,同样,Build Options 下面的Run Static Analyzer选项也最好启用,这样每次Xcode编译项目时,都会运行静态代码分析工具来检查我们的代码(Xcode的ARC 自动转换可上网搜索方法,在这里不做阐述)
-fno-obj-arc 可以禁止某些文件的ARC
属性 property
对于.h 头文件,Xcode主要是将属性定义由retain变为strong,这些属性是类对外的接口,因此定义在.h文件中
在ARC之前,开发者经常会在.m实现文件中使用class extension 来定义 private property,这样做主要是简化实例对象的手动内存管理,让property的setter方法自动管理原来对象的释放,以及新对象的retain,但是有了ARC,这样的代码就不再需要了,一般来说,仅仅为了简化内存管理,是不再需要使用property的,只有那些属于public接口的实例变量,才应该定义为property。
我们可以直接在.m类实现中定义private实例变量
NSMutableString *currentStringValue;NSMutableArray *searchResults;SoundEffect *soundEffect;
我们在使用时,虽然没有定义property,也可以直接 [self.soundEffect play],也可以[[self soundEffect] play]
作为property的最佳实践,如果你定义了某个东西为property,则你应该在任何地方都按属性来使用它。
在ARC中,所有*outlet*属性都推荐使用weak,这些view对象已经属于View Controller 的view hierarchy ,不需要再次定义为strong,唯一使用strong的outlet是File’s Owner,连接到nib的顶层对象
将outlet 定义为weak的优点是简化了viewDidUnload方法的实现。只要你保持一个对象的指针,对象就会存活,当你不需要某个对象时,可以手动设置指针为nil。
property的修饰符总结:
strong:等同于“reatain”属性称为对象的拥有者
weak:属性是weak pointer ,当对象释放时会自动设置为nil,记住Outlet应该使用Weak
unsafe_unretained:等同于之前的“assign”只有iOS4才应该使用
copy:和之前的copy一样,复制一个对象并创建strong关联
assign:对象不能使用assign,但原始类型(BOOL,int,float)仍然可以使用
ReadOnly property
在ARC之前,我们可以如下定义一个readonly property:@property(nonatomic,readonly)NSString *result;这回隐式创建一个assign property,这种用法对于readonly值来说是适当的,毕竟你何必对只读数据进行retain那,但在ARC中会报错;你必须显式使用strong,weak或unsafe_unretained,多数情况下使用strong是正确的
@property(nonatomic, strong, readonly) NSString *result;
对于readonly property,我们应该总是使用self.propertyName来访问实例变量(除了init和自定义的getter和setter方法),否则直接修改实例变量会混淆ARC并导致奇怪的Bug,正确的方法是使用class extension 重新定义 property为readwrite;
.h文件:@property (nonatomic, strong, readonly) NSNumber *temperature;
.m 文件:@property(nonatomic, strong, readwrite) NSNumber *temperature;