Objective-C内存管理使用的技术是引用计数(Reference Counting)。从开始的MRC(Manual),到后来的ARC(Automatic)。
使用ARC的好处:
1)程序员无需再写retain和release代码,很大程度上减少了开发工作量。
2)系统比程序员清楚对象什么时候该被销毁,降低了crash和leak的风险。
关于引用计数,《Objective-C 高级编程》的“开关房间的灯”例子讲得很形象,其中的对应关系如下:
1)灯,是对象。
2)人,是引用对象的变量。其实就是对象的地址,这里需要理解指针和指针指向的内容。
3)开灯:生成对象。
4)需要照明:持有对象。
5)不需要照明:释放对象。这里的释放特指release。
6)关灯:销毁对象。
上面提到引用计数机制中最核心的四种对象操作,现在来看看它们对应的方法:
1)生成对象:以alloc/new/copy/mutableCopy开头的方法
// 生成并持有一个堆中的NSObject对象,obj是对象的指针,对象的引用计数+1id obj = [[NSObject alloc] init];id obj = [NSObject new];
实践证明,copy和mutableCopy方法并不一定会生成对象,具体见:
2)持有对象:retain
3)释放对象:release
4)销毁对象:dealloc
NSAutoreleasePool重写了NSObject中的autorelease方法,一旦调用,就会crash:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];[pool autorelease]; // crash
ARC和MRC的本质一样,只是ARC自动帮程序员做了些事情。在一个app中,两者可以混用,最小单位是文件。
工程配置文件 -> 特定target -> Build Phases -> Compile Sources -> 特定文件:
-fobjc-arc // 使用ARC,Xcode4.2及以上版本的默认值-fno-objc-arc // 不使用ARC
ARC中有四种对象所有权修饰符:
1)__strong
变量强引用对象,默认值
// 两种写法等价NSObject *obj = [[NSObject alloc] init];NSObject * __strong obj = [[NSObject alloc] init];
__strong变量超出作用域时,会释放它引用的对象
2)__weak
3)__unsafe_unretained
不安全,不持有对象。如果对象被销毁,__unsafe_unretained变量会变成野指针,继续访问会导致crash,所以使用前一定要保证对象存在。
NSObject * __unsafe_unretained obj = [[NSObject alloc] init];// NSObject对象在init完,引用计数就为0,被销毁,再访问obj变量会导致crash
4)__autoreleasing
获取对象的引用计数,但其实这个函数在有些情况下并不靠谱,所以个人建议最好不用。
uintptr_t _objc_rootRetainCount(id obj)