【转】iOS夯实:ARC时代的内存管理

iOS夯实:ARC时代的内存管理

什么是ARC

Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations [1]

ARC提供是一个编译器的特性,帮助我们在编译的时候自动插入管理引用计数的代码。
最重要的是我们要认识到ARC的本质仍然是通过引用计数来管理内存。因此有时候如果我们操作不当,仍然会有内存泄露的危险。下面就总结一下ARC时代可能出现内存泄露的场景。

内存泄露类型

  1. 循环引用

    基于引用计数的内存管理机制无法绕过的一个问题便是循环引用(retain cycle)
    (Python同样也采用了基于引用计数的内存管理,但是它采用了另外的机制来清除引用循环导致的内存泄露,而OC和Swift需要我们自己来处理这样的问题[^2])

    • 对象之间的循环引用:使用弱引用避免
    • block与对象之间的循环引用:

    会导致Block与对象之间的循环引用的情况有:

    self.myBlock = ^{ self.someProperty = XXX; };  
    

    对于这种Block与Self直接循环引用的情况,编译器会给出提示。

    但是对于有多个对象参与的情况,编译器便无能为力了,因此涉及到block内使用到self的情况,我们需要非常谨慎。(推荐涉及到self的情况,如果自己不是非常清楚对象引用关系,统一使用解决方法处理)

    someObject.someBlock = ^{ self.someProperty = XXX; }; //还没有循环引用 
    self.someObjectWithABlock = someObject; // 导致循环引用,且编译器不会提醒
    

    解决方案:

    __weak SomeObjectClass *weakSelf = self;
    
    SomeBlockType someBlock = ^{
    	SomeObjectClass *strongSelf = weakSelf;
    	if (strongSelf == nil) {
        // The original self doesn't exist anymore.
        // Ignore, notify or otherwise handle this case.
    	}
    	[strongSelf someMethod];
    };
    

    我们还有一种更简便的方法来进行处理,实际原理与上面是一样的,但简化后的指令更易用。

@weakify(self)
[self.context performBlock:^{
// Analog to strongSelf in previous code snippet.
@strongify(self)

// You can just reference self as you normally would. Hurray.
NSError *error;
[self.context save:&error];

// Do something

}];

	你可以在这里找到@weakify,@strongify工具:[MyTools_iOS](https://github.com/100mango/MyTools_iOS)
	
[^2]: [How does Python deal with retain cycles?](http://www.quora.com/How-does-Python-deal-with-retain-cycles)

2. NSTimer

	一般情况下在action/target模式里 target一般都是被weak引用,除了NSTimer。
	
	~~~objective-c
	+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds
                            target:(id)target
                          selector:(SEL)aSelector
                          userInfo:(id)userInfo
                           repeats:(BOOL)repeats
	~~~
	在官方文档中:
	> target	
	The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.
	
	Timer Programming Topics :
	> A timer maintains a strong reference to its target. This means that as long as a timer remains valid, its target will not be deallocated. As a corollary, this means that it does not make sense for a timer’s target to try to invalidate the timer in its dealloc method—the dealloc method will not be invoked as long as the timer is valid.


	
	举一个例子,一个Timer的Target是ViewController.
	
	这个时候,如果我们是在dealloc方法里让timer invalidate,就会造成内存泄露.
	
	事实上,timer是永远不会被invalidate.因为此时VC的引用计数永远不会为零。因为Timer强引用了VC。而因为VC的引用计数不为零,dealloc永远也不会被执行,所以Timer永远持有了VC.
	
	因此我们需要注意在什么地方invalidate计时器,我们可以在viewWillDisappear里面做这样的工作。

  1. Transitioning to ARC Release Notes ↩︎

posted @ 2015-09-05 11:18  WillkYang  阅读(207)  评论(0编辑  收藏  举报