Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding retain cycle when using function as a block in swift

following is a code sample you can run in a playground

import Foundation

class TempNotifier {  
    var onChange: (Int) -> Void = {t in }
    var currentTemp = 72

    init() {
        // 1.
        onChange = { [unowned self] temp in
            self.currentTemp = temp
        }

        // 2.
        onChange = {[unowned self] temp in
            self.tempHandler(temp)
        }

        // 3.
        unowned let s = self
        onChange = s.tempHandler
    }

    deinit {
        println("deinit")
    }

    private func tempHandler(temp: Int) {
        self.currentTemp = temp
    }
}

var tN: TempNotifier? = TempNotifier()
tN = nil

It illustrates 3 ways of assigning a value to a block with potential retain-cycle. Case 1. and 2. create no retain cycle due to unowned self however in case 3. it seems like there is no way to break the retain cycle (deinit is never printed). As you can see, I even tried to create a local unowned reference.

Is this the desired behaviour, is it "by design"? Or am I missing something?

Thanks!

Cross-posted from https://devforums.apple.com/message/1122247

like image 620
Sash Zats Avatar asked Apr 07 '15 06:04

Sash Zats


People also ask

How do I stop retaining cycles in Swift?

For example; when we set mercedes instance to nil , the compiler cannot decrease its ARC to 1 because a Car object is still referencing the mercedes and vice versa. In order to prevent this retain cycle, we need to declare at least one of the variable as weak or unowned.

How can I stop retaining my period?

The first rule to avoid retain cycles is that an object must never retain its parent. This changes the previous diagram to the following: This is the easy case: an object should never retain its parent when it makes a pointer to the parent. Notice that the term "weak pointer" is used.

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.

How would you identify and resolve a retain cycle?

Take a look at what objects are in-memory and how much of each instance exists per object. Check for these signs of a retain cycle/memory leak: In the left panel do you see any objects/classes/views and etc on the list that should not be there or should have been deallocated?


1 Answers

Yes, this is the designed behavior.

Accessing a method without calling it, like s.tempHandler, is equivalent to a closure expression like { x in s.tempHandler(x) }. Here s is not marked unowned or weak, and hence is retained by the closure. If you want it to be captured as unowned or weak, you must explicitly write out the closure.

like image 133
newacct Avatar answered Sep 21 '22 05:09

newacct