项目设置
设置项目为ARC或者为MRC
在TARGETS -> Build Setting -> Apple LLVM 8.0 - Language - Objective C -> Objective-C Automatic Reference Counting 设置其为YES(ARC)或者NO(MRC)ARC和MRC混编
在TARGETS -> Build Phases -> Compile Sources中选择对应文件设置其Compiler Flags
- ARC项目按照MRC编译 -fno-objc-arc
- MRC项目按照ARC编译 -fobjc-arc
MRC
MRC文件一定要有dealloc 并且一定要有[super dealloc] 而且放到最后面
系统自带的方法里面没有包含alloc,new ,copy说明返回的对象都是autorelease的
autoreleasepool是一种结构,不再是OC对象作用域与普通{ }一样。
先release后设置为nil 。绝对不可以先nil,在release。
-
多对象内存管理原则
- 你想使用(占用)某个对象,就应该让对象的计数器+1 (让对象做一次retain操作)
- 你不想再使用(占用)某个对象,就应该让对象的计数器-1 (让对象做一次release操作)
- 谁retain,谁release
- 谁alloc,谁release
- 代码规范
-
Foundation
对象(OC对象) : 只要方法中包含了alloc
\new
\copy
\mutableCopy
\retain
等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次release
或者1次autorelease
-
CoreFoundation
对象(C对象) : 只要函数中包含了create
\new
\copy
\retain
等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease
或者其他release
函数
- 在MRC Block使用WeakSelf防止循环引用,但是此时有延时操作的话 可以用 malloc_zone_from_ptr(weakObj) 判断weakSelf是否存在
ARC
- 使用
Core Foundation
中malloc(size_t __size)
开辟空间之后,你仍然对其内存管理负有责任需要在适当时候使用free(void *)
以释放内存防止泄露
void *p = malloc(3);
free(p);//需要free()
-
因为ARC只对 objective-c 有效,而Core 开头的底层C语言库是没有使用编译器的特性ARC的,需要开发者手动进行内存管理(只要函数中包含了
create
\new
\copy
\retain
等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease
或者其他release
函数);并且在ARC中Core 开头的底层C语言库和OC中的库互相转换的时候需要使用(__bridge type)
进行桥接,以Core Foundation
为例进行说明。- 如果要使用
Core Foundation
,需要把数据类型进行转换,添加(__bridge type)
;但是(__bridge type)
不对程序的内存管理做任何事情,不会更换对象的所有权,原来是ARC管理的对象还继续ARC管理,MRC的还继续MRC管理
注意:(__bridge type)
只存在于ARC中,(__bridge type)
是Core Foundation
和Foundation
转换的桥梁,既可以Foundation
->Core Foundation
,同样也能达到Core Foundation
->Foundation
的效果
- 如果要使用
//Foundation -> Core Foundation
id a = [[NSObject alloc] init];
void *p = a;//void *是属于Core Foundation,ARC中会报错“Implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast” void *p = (__bridge void *)(i);
void *p = (__bridge void *)(a);//正确写法
//Core Foundation -> Foundation
void * q = 0;
id b = (__bridge id)q;
+ `Foundation` **->** `Core Foundation` 解除 ARC 的所有权
`__bridge_retained`和`CFBridgingRetain`:桥接的基础上对相关数据进行一次retained操作,防止被释放而Crash(EXC_BAD_ACCESS) 。
注意:最后一定要对p进行一次release操作(因为进行了一次retain) 否则内存泄漏
void *p;
{
id obj = [[NSObject alloc] init];
// p = (__bridge void *)obj;//错误写法 导致EXC_BAD_ACCESS
p = (__bridge_retained void *)obj;//正确写法
//或者使用下面一种写法 效果是一样的 都相当于[p retain] 对p进行一次retain操作
p = (void*)CFBridgingRetain(obj);//正确写法
}
NSLog(@"class=%@", [(__bridge id)p class]);//如果使用错误写法 这里访问的是僵尸对象
CFRelease(p);//切记最后一定要进行一次release操作 否则内存泄漏
+ `Core Foundation` **->** `Foundation` 给予 ARC 所有权
`__bridge_transfer`和`CFBridgingRelease`:桥接的接触上对相关数据进行了一次release操作,就不用再显式地对`Core Foundation` 数据进行`CFRelease(CFTypeRef cf)`操作了
const char *bytes;
CFStringRef coreStr;
bytes = CFAllocatorAllocate(CFAllocatorGetDefault(),6,0);
strcpy(bytes,"wp");
coreStr = CFStringCreateWithCStringNoCopy(NULL,bytes,kCFStringEncodingMacRoman,NULL);
//NSString *str = CFBridgingRelease(coreStr);
NSString *str = (__bridge_transfer NSString *)coreStr;//不用再release操作了
总结:
-
Core Foundation
对象类型不在 ARC 管理范畴内,需要自己管理 -
__bridge
只做类型转换,但是不修改对象(内存)管理权,原来是ARC管理的还用ARC,原来MRC管理的继续用MRC -
__bridge_retained
(也可以使用CFBridgingRetain
)将Objective-C的对象转换为Core Foundation
的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease
或者相关方法来释放对象; -
__bridge_transfer
(也可以使用CFBridgingRelease
)将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。
END