工作原理
自动计数(ARC)是一个编译期间工作的能够帮你管理内存的技术。 ARC在编译期间为每个Objective-C指针变量添加合适的retain, release, autorelease等函数,保存每个变量的生存周期控制在合理的范围内,以期实现代码上的自动内存管理。 In order for the compiler to generate correct code, ARC imposes some restrictions on the methods you can use, and on how you use toll-free bridging (see “Toll-Free Bridged Types”); ARC also introduces new lifetime qualifiers for object references and declared properties.
功能
ARC使得你不需要再思考何时使用retain,release,autorelease这样的函数来管理内存,它提供了自动评估内存生存期的功能,并且 在编译期间自动加入合适的管理内存的方法。编译器也会自动生成dealloc函数。
新规则
-
不能直接调用dealloc方法,不能重载或直接调用retain, release, retainCount,或 autorelease等方法。但可以通过@selector(retain), @selector(release)这样的形式调用。
-
用户自定义的dealloc方法,不能调用[super dealloc] ,编译器会自动帮你添加这个代码。
-
对Core Foundation-style 的对象,仍可以使用CFRetain, CFRelease等方法。
-
不能使用NSAllocateObject或NSDeallocateObject去创建对象,请使用alloc方法。
-
在c语言中的结构体中,不能再使用对象指针。请放弃C结构体,使用Objective-C的类。
-
id和void*之间没有隐式的类型转换,请使用显式类型转换。
-
不能使用NSAutoreleasePool *pool= ARC提供了@autoreleasepool语句块。
关于对象的生命周期
设置成weak的属性,不会影响对象的生命周期,如果引用的对象已经被释放,引用会指向nil。 strong引用:设置成strong的属性,会影响对象的生命周期。
例如:
@property(strong) MyClass *myObject;
和:
@property(retain) MyClass *myObject;
是等效的。
又例如:
@property(weak) MyClass *myObject;
和:
@property(assign) MyClass *myObject;
在多数情况下等效,但当instance被释放时,设置为weak的引用会指向nil。 可用的限定词: strong, 默认的 weakunsafe_unretained,和weak的区别是当对象被释放时,引用不指向nil。 autoreleasing,当方法的参数是id*,且希望方法返回时对象被autoreleased,可以添加autoreleasing限定词。 使用weak时要特别小心,如果weak引用的对象在此次使用之前被使用过一次,那么它一直存在,直到autoreleasepool释放它,否则就是nil。
例如:
NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; string = NSLog(@"string: %@", string); //此时string为空,因为weak类型不影响对象的生命周期,对象刚创建就释放了。
其他特性: 使用strong, weak, autoreleasing限定的变量会被隐式初始化为nil。
例如:
- (void)myMethod { NSString *name; NSLog(@"name: %@", name); //会输出null }
weak与assign很像,不同在于如果指向的数据被释放了,那么这个指向nil unsafe_unretained 相当于assign,指向的数据如果被释放,这个指向原来的地址。
禁用在Xcode中的特定文件的ARC
选择项目->Build Phases->Compile Sources,,给需要禁止arc的文件添加 “-fno-objc-arc”(双击该文件)编译标志(Compiler Flags)。
如下图
注意事项
- 不可以使用retain,retainCount,release,autorelease 用@select()这样的调用也不行.属性命名不能以new开头。
-
若重写一个类子类的dealloc,不应调用[super dealloc],当然也不用写什么release释放一些什么对象,只是处理一些你觉得必要处理的事情吧,比如中止一个还没有完成的网络请求.
-
不能使用NSAllocateObject和NSDeallocateObject
-
你不能在c结构中使用对象,更好的方式是使用Objective-c类来代替.
-
在id和void*之间不能隐士转换,必须指明相应转换的生命周期。
-
不能使用NSAutoreleasePool对象,ARC使用@autoreleasepool{}块代替。
Core Foundation 对象与Objective-c对象之间的赋值,函数调用参数相互转化时需要用到的关键字
__bridge
简单赋值,不会影响两边对象的retain count.
__bridge_transfer
赋值后释放右边的对象
__bridge_retained
赋值后也保留不释放右边的对象
举例:
-(void)test { CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(),"C String", kCFStringEncodingUTF8); // 创建 retainCount = 1 id unknownObjectType = (__bridge id)coreFoundationString; // 简单赋值,不变,retainCount = 1 CFStringRef anotherString = (__bridge_retained CFStringRef)unknownObjectType; // 保留赋值,加一,retainCount = 2 NSString *objCString = (__bridge_transfer NSString *)coreFoundationString; // 释放赋值,减一,retainCount =1;由于NSString*默认strong,加一,retainCount = 2 NSLog(@"String = %@", objCString); objCString = nil; // 不再指向原内存,原内存减一,retainCount = 1 CFRelease(anotherString); // 释放,减一,retainCount = 0 }
在c型的结构中使用objective-c对象
使用void*代替id;或者使用__unsage_unretained 修饰objective-c对象