1.oc 没有垃圾回收机制,而是引用计数模型,使用retain 和 release 控制对象,以避免内存泄漏,如果retain 一个对象,那么它的引用计数增加,这个计数表示有多少对象引用了改对象,如果不在需要一个对象,可以发送一个 release.引用计数为零时这个对象会被销毁
当我们init 一个对象,引用计数曾1,当被释放掉,引用计数再次归零,
手动retain/release 可能引入错误:有些对象已经被释放掉,但开发者二次释放,导致程序崩溃,假如开发者忘记释放对象,又会导致内存泄漏,为此苹果引入自动引入计数。
自动引用计数
自动引用计数它不需要手动追踪引用计数,而是在合适的时机自动增或减少引用计数。
-
weak和strong 引用配合使用防止循环引用这样就会避免父对象和子对象同时引用对方,导致内存泄漏。
-
Core Foundation (Core Graphics、Core Text)对象,ARC环境下,编译器不会自动管理CF对象的内存,我们需要手动管理,可以桥接到Coca对象,这样编译器就知道使用ARC管理转换之后的Core Foundation对象这里需要用_bridge
-
@autoreleasepool 取代之前的 NSAutoReleasePool机制。
在使用ARC和Coca应用中内存管理细节不再会导致安全隐患,涉及到的内存管理崩溃变得越来越少,但是还是有些地方会导致内存管理的问题,因为Core Foundation对象依然使用CFRetain和CFRelease C语言中malloc 和free 也会用到
bridge, bridge_transfer,__bridge_retained 来进行内存管理
- __bridge:把CFObject类型转换成NSObject类型,但是对象的持有者依然是CFObject,所以我们不需要对CFObject做内存管理(跟wifi相关的)
从 NSBundle 读取图片数据 NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]; CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]], NULL);
如果上面不添加 bridge ,在ARC环境下,系统会给出错误提示和错误修正,点击错误提示的话,系统会为我们自动添加 bridge ,因为在OC与CF的转化时只涉及到对象类型没有涉及到对象所有权的转化,所以上述代码不需要对CF的对象进行释放,即不需要添加CFRelease
- __bridge_transfer: 常用在CF对象转化成OC对象时,将CF对象的所有权交给OC对象,此时ARC就能自动管理该内存,作用同CFBridgingRelease()由ARC来代替我们管理内存
如果非ARC的时候,我们可能需要写下面的代码。
// p 变量原先持有对象的所有权
id obj = (id)p;
[obj retain];
[(id)p release];
那么ARC有效后,我们可以用下面的代码来替换:
// p 变量原先持有对象的所有权
id obj = (__bridge_transfer id)p;
可以看出来, bridge_retained 是编译器替我们做了 retain 操作,而 bridge_transfer 是替我们做了 release。
- bridge_retained:bridge_transfer 相反,常用在将OC对象转化成CF对象,且OC对象的所有权也交给CF对象来管理,即OC对象转化成CF对象时,涉及到对象类型和对象所有权的转化,作用同CFBridgingRetain()需要我们手动来管理内存
先来看使用 __bridge_retained 关键字的例子程序:
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;
此时retainCount 会被加1;
从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。如果不是ARC代码,类似下面的实现:
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
ARC如何获取retainCount
NSLog(@“Retain count is %ld”, CFGetRetainCount((__bridge CFTypeRef)myObject));
来来来举个例子:
NSString *string = [NSString stringWithFormat:@""];
CFStringRef cfString = (__bridge CFStringRef)string;
CFStringRef cfStr = (__bridge_retained CFStringRef)string;
CFRelease(cfString);// 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release
CFRelease(cfStr);
使用 __bridge_retained 可以通过转换目标处(cfStr)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString变量也变释放,cfStr 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。
CFStringRef cfString= CFURLCreateStringByAddingPercentEscapes( NULL, (__bridge CFStringRef)text, NULL, CFSTR("!*’();
:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
NSString *ocString = (__bridge_transfer CFStringRef)cfString;
所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。
总结:
Core Foundation 对象类型不在 ARC 管理范畴内
Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
3. bridge, bridge_transfer和__bridge_retained 是CF和OC的桥梁
如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁以及各种对象的生命周期是怎么样的
总结:
1.Core Foundation 对象类型不在 ARC 管理范畴内
2.Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
3… bridge, bridge_transfer和__bridge_retained 是CF和OC的梁
如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁以及各种对象的生命周期是怎么样的