iOS 无论是在MRC 还是ARC情况下 OC 都是用引用计数来管理内存!
内存管理的原则是: 谁创建 谁来释放 谁引用,谁管理
例如MRC下:
NSObject * a = [NSObject alloc] init]; a 引用计数为 1
NSObject * b; //相同类型局部变量b
b = [a retain] //b这个时候可以使用a a的引用计数+1 = 2
[a realse]; a的引用计数为1
[a realse]; a的引用计数为0
alloc 、new、 copy、 mutableCopy 引用计数 = 1 生成并持有对象
retain 引用计数+1 并持有这个对于
strong 引用计数+1 MRC下会做一次retain ARC下省略
addobject 类似的 想要持有这个对象 引用计数+1
release 引用计数 - 1
dealloc 引用计数为0的时候调用
ARC管理方法:
在ARC内存管理机制中,id和其他对象类型变量必须是以下四个ownership qualifiers其中一个来修饰:
__strong 强引用
__weak 弱引用
__unsafe_unretained 它是不安全的。它跟__weak相似,被它修饰的变量都不持有对象的所有权,但当变量指向的对象的RC为0时,变量并不设置为nil,而是继续保存对象的地址;这样的话,对象有可能已经释放,但继续访问,就会造成非法访问(Invalid Access)
__autoreleasing
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// put object into pool
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
/* 超过autorelease pool作用域范围时,obj会自动调用release方法 */
引入ARC之后,写法比之前更加简洁:
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
ARC需要注意的事项?
1.过度使用 block 之后,无法解决循环引用问题
由于Core Foundation 框架并不支持 ARC,此时编译器不知道该如何处理这个同时有 ObjC 指针和 CFTypeRef 指向的对象,所以除了转换类型,还需指定内存管理所有权的改变,可通过 __bridge、__bridge_retained 和 CFBridgingRetain、__bridge_transfer 和 CFBridgingRelease。
2.遇到底层 Core Foundation 对象,需要自己手工管理它们的引用计数时,我们需转换关键字,作为桥接转换以解决 Core Foundation 对象与 Objective-C 对象相对转换的问题:
__bridge:使用__bridge标记可以在不修改相关对象的引用计数的情况下,将对象从Core Foundation框架数据类型转换为Foundation框架数据类型(反之亦然)。
CF和OC对象转化时只涉及对象类型不涉及对象所有权的转化
只是声明类型转变,但是不做内存管理规则的转变
CFStringRef s1 = (__bridge CFStringRef) [[NSString alloc] initWithFormat:@"Hello, %@!", name];
只是做了 NSString 到 CFStringRef 的转化,但管理规则未变,依然要用 Objective-C 类型的 ARC 来管理 s1,你不能用 CFRelease() 去释放 s1。
__bridge_retained:会将相关对象的引用计数加 1,并且可以将Core Foundation框架数据类型对象转换为Foundation框架数据类型对象,并从ARC接管对象的所有权。
NSString *s1 = [[NSString alloc] initWithFormat:@"Hello, %@!", name];
CFStringRef s2 = (__bridge_retained CFStringRef)s1;
// or CFStringRef s2 = (CFStringRef)CFBridgingRetain(s1);
// do something with s2
//...
CFRelease(s2); // 注意要在使用结束后加这个
__bridge_transfer:可以将Foundation框架数据类型对象转换为Core Foundation框架数据类型对象,并且会将对象的所有权交给ARC管理,也就是说引用计数交由ARC管理;
__bridge_transfer or CFBridgingRelease
CFStringRef result = CFURLCreateStringByAddingPercentEscapes(. . .);
NSString *s = (__bridge_transfer NSString *)result;
//or NSString *s = (NSString *)CFBridgingRelease(result);
网友评论