一、ARC相对MRC来说,减轻了程序员的大部分内存管理工作,使用ARC的时候也需要十分清除内存管理的原理,不然可能带来一些很难调试的问题。下面是ARC下面需要注意的一些问题
1)对象互相引用,形成引用循环。引用循环是基于引用计数无法避免的问题,因为Objetive-C实质上还是一种编译时期的内存管理技术,没有引入GC,所以引用循环问题还是需要程序员手工处理。
具体的处理办法就是使用weak,assign,_unsafe_unretained 修饰变量,打破引用循环。
对象引用循环可能导致的问题,对象持久不释放,比如内存中存在两个VC,收到通知时,同一个方法执行两次等诡异的现象(大部分人通知的移除放在dealloc里面,放在viewWillAppear中可以避免此问题,但也可能引入更多问题)。
2)使用ARC的时候,小心处理assign修饰的对象,assign只是简单的赋值,不对对象的引用计数做改变,对象释放了,这个assign记录的对象地址还是不变。向这个对象发送消息的时候,会偶先Crash。
如果这个对象释放之后,对象内存区域数据,还是没有变化,是不会crash的。
这一类crash是偶先的,有可能crash极难重现,想要暴漏这些问题,尽量不要使用assign、_unsafe_unretained ,而使用weak。
有时候assign、_unsafe_unretained是无法避免的,例如NSNotification的observer,KVO的observer,NSValue valueWithNonretainedObject;
还有可能是因为历史遗留代码中使用到assign、_unsafe_unretained。
3)多线程传递autoRelease对象可能引起Crash
autorelease的对象使用一种延迟释放的技术,将对象暂时记录下来,当autorelease pool drain的时候,向对象发送release消息。
autorelease跟runloop存在一定的联系,runloop的每一次循环中,会默认创建一个autoreleasepool,因此如果在一个线程中,没有创建runloop并且没有创建autoreleasepool,autorelease对象可能存在泄漏。
跨线程传递一个autorelease对象的时候,有可能对象在原来的线程中被提前释放掉。
例如下面的代码:
由于参数没有retain,有可能autorelease参数会被提前释放
- (id) method { NSInvocation *invocation = [nsinvocation alloc] initWith ... //参数是autorelease的 [invocation setArg:&[nsdata data] atIndex:index] //延迟调用 invocation performselector:@selector(invoke) afterdelay: }
这里还有一个ARC下面的例子:
23down voteaccepted
|
I am guessing you are using ARC? The problem is with the line The solution is that you must give a pointer to a non-retained type to
or:
|
http://stackoverflow.com/questions/22018272/nsinvocation-returns-value-but-makes-app-crash-with-exc-bad-access
二、MRC 自动转换为ARC是否会引起Crash
有可能存在这样的情况,请见博客 《ARC下面的对象被释放的bug》