Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift retain cycle explanation

Here is my custom view:

class CustomVIew: UIView {

    deinit {
        print("custom view deinit")
    }

    var onTapViewHandler: (()->Void)?
}

and the View Controller:

class ViewControllerB: UIViewController {

    var customView: CustomVIew!

    deinit {
        print("B deinit")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let customView = CustomVIew()
        customView.onTapViewHandler = { [unowned self] in
            self.didTapBlue()
        }
        customView.frame = CGRect(x: 50, y: 250, width: 200, height: 100)
        customView.backgroundColor = UIColor.blueColor()
        view.addSubview(customView)

        self.customView = customView

    }

    func didTapBlue() {

    }
}

When the controller is popped from the navigation stack, everything is fine:

B deinit
custom view deinit

But when I replace this code:

customView.onTapViewHandler = { [unowned self] in
     self.didTapBlue()
}

with this:

 customView.onTapViewHandler = didTapBlue

then, nothing is printed on the console. The CustomView and ViewController are not released, why?

Why does customView.onTapViewHandler = didTapBlue capture a reference to self?

like image 359
Yang.ZhiXiao Avatar asked Aug 14 '16 05:08

Yang.ZhiXiao


People also ask

What causes retain cycle Swift?

— in order to deallocate an object from memory, its ARC value must be zero. However, when some two object refers each other via strong references, they prevent the compiler from deallocating either object because their ARC value would always be 1. That is called a retain cycle.

What is retain count in Swift?

An essential concept in ARC is the retain count, which is a number that keeps track of how many objects are “holding onto” to another object. ARC only applies to reference types such as classes, and not to value types like structs. Value types are copied, so they don't work with references.

Which of the following can cause a retain cycle?

Structs and Classes A choice between a struct and a class can cause a retain cycle. Both structs and classes can have constants, variables, functions and protocols.


1 Answers

Swift function is a type of closure. So like closure(Block in objective c) does functions can capture references.

when customView.onTapViewHandler = didTapBlue gets executes a reference to self ie ViewControllerB reference in this case will be captured by the function call.

Same time ViewControllerB's view holds strong reference to CustomVIew so it makes retain cycle.

About using unowned, Apple document says:

Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle.

That means no circular reference and retain cycle.

like image 65
renjithr Avatar answered Oct 12 '22 12:10

renjithr