ARC delegate memory management

2019-07-23 12:51发布

问题:

In Apple's docs it says

You may implement a dealloc method if you need to manage resources other than releasing instance variables. You do not have to (indeed you cannot) release instance variables, but you may need to invoke [systemClassInstance setDelegate:nil] on system classes and other code that isn’t compiled using ARC.

Does this include UIKit and Framework delegates, for example, the parent of a UIPageViewController has the delegate UIPageViewControllerDelegate - does this have to be nilled in the dealloc?

回答1:

When you have a relationship between the a parent controller and its view, where the parent controller acts as the views delegate, one of those relationships must not retain the other, otherwise you will have a retain cycle and a memory leak.

There are two ways to do this:

  • There first is to mark the delegate as __unsafe_unretained. If you do this you will need to manually nil out the reference in the dealloc of the controller.

  • The second is to use a weak reference. Most of ARC happens at compile time. This helps to save battery drain by reducing the CPU cycles that would otherwise occur with a garbage collector. However, for weak references, there's a run-time process that maintains a map of these variables, observes them, and nils them out as required. This is why weak references required iOS5.1 - its not just a compiler feature.

  • If you use too many weak references, it can be a performance overhead. In practice this will hardly ever be a concern.

Summary

  • No you don't need to manually nil it out if you use weak references. Check that you don't have a memory like via a retain cycle of strong references.
  • Only use __unsafe_unretained (aka 'assign') if you really have to.
  • The same rules apply for UIKit and framework classes. The nice thing is that they're very consistent.

Update

  • Correcting my dodgy comment: If your delegate goes away before the controller does, then you will need to nil it off the controller manually - thanks @borrden.