设置ARC有效的编译命令:
-fobjc-arc
Xcode 4.2 默认设定为对所有的文件 ARC 有效
规则:
ARC有效情况下, 必须遵守的规则
不能使用 retain/release/retainCount/autorelease
不能使用 NSAllocateObject/NSDeallocateObject
须遵守内存管理的方法命名规则
不要显式调用 dealloc
使用 @autoreleasepool 块替代 NSAutoreleasePool
不能使用区域 (NSZone)
对象型变量不能作为 C 语言结构体 (struct/union) 的成员
显式转换 "id" 和 "void *"
对象型变量不能作为 C 语言结构体 (struct/union) 的成员
虽然是 LLVM 编译器 3.0, 但不论怎样, C 语言的规约上没有方法来管理结构体成员的生存周期. 因为 ARC 把内存管理的工作分配给编译器, 所以编译器必须能够知道并管理对象的生存周期. 例如 C 语言的自动变量 (局部变量) 可使用该变量的作用域管理对象. 但是对于 C 语言的结构体成员来说, 这在标准上就是不可实现的.
要把对象型变量加入到结构体成员中时, 可强制转换为 void * 或是附加前面所述的 __unsafe_unretained 修饰符 (__unsafe_unretained 修饰符的变量不属于编译器的内存管理对象)
显式转换 id 和 void *
ARC 有效时这便会引起编译错误ARC 无效
id 变量强制转换 void * 变量并不会出问题
id obj = [[NSObject alloc] init];
void *p = obj;
更进一步, 将该 void * 变量赋值给 id 变量中, 调用其实例方法, 运行时也不会有问题.
id o = p;
[o release];
ARC 有效
id 型或对象型变量赋值给 void * 或者逆向赋值时都需要进行特定的转换. 如果只想单纯地赋值, 则可以使用 "__bridge 转换".
id obj = [NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;
像这样, 通过 "__bridge 转换", id 和 void * 就能够相互转换.
但是转换为 void * 的 __bridge 转换, 其安全性与赋值给 __unsafe_unretained 修饰符相近, 甚至会更低. 如果管理时不注意赋值对象的所有者, 就会因悬垂指针而导致程序崩溃.
__bridge 转换中还有另外两种转换, 分别是 "__bridge_retained 转换" 和 "__bridge_transfer 转换"
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;
__bridge_retained 转换可使要转换赋值的变量也持有所赋值的对象.
ARC 无效
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];__bridge_retained 转换变为了 retain.
__bridge_transfer 转换提供与此相反的动作, 被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放
id obj = (__bridge_transfer id)p;
ARC 无效时 =>
id obj = (id)p;
[obj retain];
[(id)p release];
__bridge_retained 转换与 retain 类似, __bridge_transfer 转换与 release 相似. 在给 id obj 赋值时 retain 即相当于 __strong 修饰符的变量
如果使用以上两种转换, 那么不使用 id 型或对象型变量也可以生成/持有以及释放对象. 虽然可以这样做, 但在 ARC 中并不推荐这种方法.void *p = (__bridge_retained void *)[[NSObject alloc] init];
NSLog(@"class=%@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;该源代码与 ARC 无效时的下列源代码相同
ARC 无效
id p = [NSObject alloc] init];
NSLog(@"class=%@", [p class]);
[p release];这些转换多数使用在 Objective-C 对象与 Core Foundation 对象之间的相互变换中
网友评论