Three methods of removing cyclic references in Swift

Swift is likely to cause circular references during the use of closures, which are similar to circular references in OC

Now suppose I have two controllers, click on the first controller jump will jump to the second controller, the second controller pop will come back when deinit

Three methods of removing cyclic references in Swift
controller simple jump

I just write the following code in the B controller:

  • Define a closure property //———1. define a closure property — the / * closure has a parameter of type String, finishedCallBack: / var (no return value (str: _) (-> String))?
  • Defines a function whose arguments are the same as the type of the closure property, and then the closure parameter is assigned to the property
Func demo (finished: @escaping (str: _) (-> String) {self.finishedCallBack}) = finished
  • Defines a function that performs this closure internally
Func secondDemo () {let finishedHandler = self.finishedCallBack {finishedHandler ("secondDemo is running")}}
  • Finally, the demo () and secondDemo (two) functions are executed in viewDidLoad (Demo), which is the closure of the execution of the secondDemo () is called the closure
Override func (viewDidLoad) {super.viewDidLoad (Demo) {print ("in (string) / (string) ----/ (self.view!)")} (secondDemo)}

As shown in the above code:

  • When I define this closure, the closure is internally referenced by self, and then the closure performs a copy operation on the self, that is, the closure holds the controller
  • This closure is assigned to the closure property, so the closure property has a strong reference to the controller
  • The closure property is strongly referenced by the controller, so they form a circular reference

As shown in the following figure:

Three methods of removing cyclic references in Swift
closure loop reference

This time, when I go back to the second controller page pop, the deinit method does not call:

See console print:

Three methods of removing cyclic references in Swift
cycle reference after the console print results

How do I break the cycle reference?

Here are three ways:

  • Method 1: OC method, in OC, can be __weak typeof (self) weakSelf = self;
    in Swift, there are similar methods:
Override func (viewDidLoad) {super.viewDidLoad (OC) / * method, the method of var / weak weakSelf = self demo in if let (string) {wSelf = weakSelf {print ("/ (string) ----/ (wSelf.view)" (secondDemo)}})}

Swift is weak var weakSelf = self this code

  • Method two: [weak self] modified closure
Override func viewDidLoad (super.viewDidLoad)) {/ * (method two: [weak self] modified {[weak / demo closure (string) self] in if let weakSelf = self {print ("/ (string) ----/ (weakSelf.view)" (secondDemo)}})}
  • Method three: [unowned self] modified closure
Super.viewDidLoad (three): [unowned self] / * method modified closure / demo (string) {[unowned self] in ("print / (string) ----/ (self.view)" (secondDemo)})}
Note: the difference between the two methods and method three is the second method when the controller is destroyed, the self pointer will point to nil, and the third method when the controller is destroyed, self is not a pointer to nil pointer, it will form a wild pointer, therefore, third kinds of methods to remove the circular reference is not recommended, there is may cause some problems

After the loop reference is dropped, the console print displays: the deinit method is called

Three methods of removing cyclic references in Swift
release cycle reference after console printing