ARC学习笔记
1. ARC并不是自动管理内存,与AutoreleasePool不同,ARC是LLVM 3.0编译器提供的特性,编译器自动在适当的地方插入retain、release、autorelease,所以还是手动管理内存,对象不会像AutoreleasePool一样在内存中存放很久。
2. ARC只能工作于Objective-C对象,如果应用使用了Core Foundation或malloc()/free(),此时需要你来管理内存。
3. 虽然ARC管理retain和release,但并不表示不需要处理内存问题,strong指针会保持对象的生命,所以有时候为了回收内存,自己要将其设为nil,以便释放内存,否则内存可能会被用光。
4. property的修饰符有一定变化。a)strong等同于retain;b)weak是弱指针,当对象释放时会自动设置为nil;c)unsafe_unretained等同于assign只有iOS4才应该使用;d)copy和以前的copy一样,复制一个对象并创建strong关联;e)assign不能用于对象,应该用于BOOL、int和float等值类型。
5. 如果dealloc方法只是释放对象,则不需要此方法,但如果dealloc中处理了其它非内存资源释放,如定时器、Core Foundation对象,则仍然需要在dealloc方法中进行手动释放,但不能调用[super dealloc]。
6. 由于ARC只作用于Objective-C对象,有时候要用到Core Foundation对象,两者之间的转换可以使用toll-free bridging来很方便地完成,例如NSString和CFStringRef。编译器必须知道由谁来负责释放转换后的对象,如果你把一个Objective-C对象当作Core Foundation对象来使用,ARC将不再负责释放该对象,在两种对象之间进行转换时,要显示地移交或者接受权利。
7. 函数参数和局部变量一样,都是strong指针,这种对象在函数入口处会被retain,并且对象会持续存在直到指针被销毁。
8.
1 - (NSString *)escape:(NSString *)text { 2 return [(NSString *)CFURLCreateStringByAddingPercentEscapes( 3 NULL, 4 (CFStringRef)text, // 这里需要进行bridging casts,将text临时当作CFStringRef对象来使用。 5 NULL, 6 (CFStringRef)@"!*'();:@&=+$,/?%#[]", // 这里不用bridging casts,因为这是常量,不需要释放! 7 CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) 8 autorelease]; 9 }
9. __bridge转换不仅仅局限于Core Foundation对象,某些API使用void *指针作为参数,允许你传递任何东西的引用,比如Objective-C对象、Core Foundation对象或malloc()内存缓冲区等等。那么传参数的时候将这些对象转换为void *,如:[UIView beginAnimations:nil context:(__bridge void *)someObject],在使用这些参数的地方再将其转换回来,如:MyClass *myObject = (__bridge MyClass *)context。
10. 内存管理权的移交有三种情况,a)使用CFBridgingRelease()或__bridge_transfer将管理仅移交给Objective-C;b)使用CFBridgingRetain()或__bridge_retained将管理权移交给Core Foundation;c)使用__bridge来临时使用某对象,不改变管理权。
11. 在ARC之前只有成员变量才会默认设为nil,在arc中局部对象指针会被设为nil,局部值类型和值类型指针还是随机数。
12. 所有的Core Foundation对象类型都与Objective-C能够toll-free bridged,但是UIColor不能,因为UIColor与CGColor并不是toll-free bridged,所以把CGColor放入NSArray要强制转换为id类型。
13. property中的属性名不能以new开头,除非将getter指定指定为另外一个名字,@property NSString *newTitle;会出错,@property (getter=theNewTitle) NSString *newTitle;正确。
14. autorelease pool变成了一种语言结构,而不是以前的类,@autoreleasepool{}比NSAutoreleasePool快六倍。在一个很大的循环中,有时候循环xx次进行一次NSAutoreleasePool清除工作,但其实这是不必要的,每循环一次清一次也无所谓,现在@autoreleasepool指令比NSAutoreleasePool快六倍,在循环中直接使用也不用担心性能问题。
15. block会捕获自己使用到的所有变量,如果用到成员变量,那么成员变量所在的类会被retain,这样这个类就不会被释放,解决办法是使用局部变量,NSString *text = self.artistName;,然后在block中使用text,而不是self.artistName,就不会出现问题。
16. 有时候block避免不了使用self对象,ARC以前可以创建一个局部的__block对象,把self值赋值过去,如:__block MyClass *blockSelf = self;,在block中引用这个__block局部变量来访问self的属性都不会retain self,但是在ARC中即使使用了__block来标记这个局部变量,它也是强引用的,这时__block的唯一功能是允许你修改已捕获的变量。ARC的解决办法是定义弱引用:__weak MyClass *weakSelf = self;,这样weakSelf引用了self,但不进行retain,在block中捕获weakSelf而不是self,因此不存在所有权回环。在简单应用中block属于self,所以block不可能在self被释放后还能被调用,有时候在block中检查这个weakSelf被认为是不必要的,但是如果block被异步调用,则创建强引用来保持对象存活就有必要了,因此在ARC中使用block,而且要避免捕获self,可以这样:
1 - (void)doSomething 2 { 3 __weak weakSelf = self; 4 block = ^() { 5 id strongSelf = weakSelf; 6 if ( strongSelf != nil ) { 7 // do stuff with strongSelf 8 } 9 }; 10 }
17. 如果创建一个对象,等待5秒后执行某一block,然后释放掉该对象,在ARC以前应该这样:
1 - (void)doSomething 2 { 3 MyClass *object = [[MyClass alloc] init]; 4 object.block = ^(void) { 5 // do stuff 6 [object autorelease]; 7 }; 8 [object launchAfter:5]; 9 }
在ARC中不允许使用autorelease,所以去掉释放那一行,那么这样会导致block永远不会被执行,因为object对象在此函数返回后被释放。解决办法是定义__block类型变量,这种类型是强引用,且block中能修改其值,然后在block中将些变量设为nil,如下:
1 - (void)doSomething 2 { 3 __block MyClass *object = [[MyClass alloc] init]; 4 object.block = ^(void) { 5 // do stuff 6 object = nil; 7 }; 8 [object launchAfter:5]; 9 }
18.
1 - (void)doSomething 2 { 3 NSString *string; 4 @autoreleasepool { 5 string = [NSString stringWithFormat:…]; 6 } 7 // the string object is still alive here 8 }
19.
1 - (void)doSomething 2 { 3 __autoreleasing NSString *string; 4 @autoreleasepool { 5 string = [NSString stringWithFormat:…]; 6 } 7 // the string object is still deallocated here 8 NSLog(@"%@", string); // crash! 9 }
20. 编写自己的out-parameter方法:
1 - (NSString *)fetchKeyAndValue:(__autoreleasing NSNumber **)theValue 2 { 3 NSString *theKey; 4 NSNumber *theValue; 5 6 // do whatever you need to do here 7 8 *value = theValue; 9 return theKey; 10 }
21. Core Foundation对象不能autorelease,autorelease完全纯属于Objective-C,有些人通过转换Core Foundation对象为id,再调用autorelease,这在ARC中明显不能工作,因为不能调用autorelease。