原文地址
从开始的MRC(Manual Reference Counting)到后来ARC(Automatic Reference Counting),包括CoreFoundation的内存管理都遵守引用计数的基本原则。
在MRC环境下,你使用alloc/new/copy/mutableCopy这些开头的方法创建了一个对象,调用retain方法返回对象,那么你就会拥有这个对象,新创建对象的引用计数器为1。当你不用的时候,你就需要手动的去release一次(引用计数器减1)
在ARC环境下, 你使用alloc/new/copy/mutableCopy这些开头的方法创建了一个对象,xcode帮你在创建对象的时候添加内存管理的代码.
举一个例子,假设有一个方法,[STObject newObject]
- (instancetype)newObject {
return [[[[self class] alloc] init] retain];
}
我们应该这么使用,如果我们最后不release,就会导致Object被泄漏。
STObject *object = [STObject newObject];
// do something
[object release];
那么就产生了以下几个问题:
关键是看在那种环境(MRC or ARC)下创建对象#####
MRC下实现了一个newObject方法,该方法遵守约定的原则,返回值会retain 引用计数+1,然后在ARC下调用该方法创建对象 (xcode帮你添加内存管理的代码,只要MRC管理好对象的引用计数器就没问题)
MRC下实现了一个newObject方法,该方法 没有 遵守约定原则,返回autorelease的对象,然后在ARC下调用该方法创建对象 (MRC没有管理好对象的引用计数器,会引起野指针访问)
ARC下实现了一个newObject方法,然后在MRC下调用newObject方法创建对象,使用完成之后release (需要程序猿手动管理)
ARC下实现了一个newObject方法,然后在MRC下调用newObject方法创建对象,使用完成之后没有release (对象没有手动管理导致内存泄露)
最终测试结果如下:
场景1,3下运行正常
场景2下会crash,访问坏内存( 野指针错误)
场景4下产生内存泄露
总结:
不管创建对象的代码是写在MRC环境还是ARC环境,关键看调用创建对象的代码是在哪一个环境
如果是在MRC环境创建对象,需要程序猿手动管理对象的引用计数器
如果是在ARC环境创建对象,xcode帮你添加内存管理的代码,只要MRC管理好对象的引用计数器就没问题
分析###
为什么场景2会crash呢?这是由于ARC环境下,我们编译器如果看到你是以alloc/new/copy/mutableCopy等开头的方法创建了对象,则会在使用的最后插入一次release/autorelease操作,由于返回的是autorelease的对象,又被release了一次,所以导致野指针。
场景4产生泄漏的原因也是一样,MRC下编译器发现该方法是new等开头的时候,方法结束的时候不会插入release语句,场景4使用的过程中,没有对newObject进行release,所以会产生泄漏。
如果我们仅使用MRR或者ARC的话,这种问题一般不会出现。这种问题的出现一般是当ARC/MRR混编的时候,由于一些编写的不规范导致的,所以在写代码的过程中,遵守规范是很有必要的。
MRC环境
如果我们自己编写alloc/new/copy/mutableCopy开头的方法的时候,MRC下一定不要忘了返回retain的对象,同样当我们使用alloc/new/copy/mutableCopy的方法创建对象的时候,也不能忘了在用完之后release。