WildCat
WildCat

Reputation: 2031

How to set a weak reference to a closure/function in Swift?

In HMSegmentedControl, I'd like to set the segmentedControl.indexChangeBlock to an instance method to handle the action. The official example is: https://github.com/HeshamMegid/HMSegmentedControl/blob/master/HMSegmentedControlExample/HMSegmentedControlExample/ViewController.m (Line 63 ~ 68), but that's Objective-C.

In Swift, functions are first class citizens. So I wanna set an instance method to this block property.
But my code would lead to a circular reference, it seems that I should define a weak reference:

class ExampleVC: UIViewController {
    var segmentedControlIndex: Int = 0

    override func viewDidLoad() {
      let segmentedControl3 = HMSegmentedControl(sectionImages: ... , sectionSelectedImages: ... )
      segmentedControl3.frame = ...
      segmentedControl3.indexChangeBlock = someInstanceMethod
    }

    func someInstanceMethod(index: Int) {
      segmentedControlIndex = index
    }
}

However, I cannot define a weak reference to a non-class type. What can I do? Is it legal to do this?

Upvotes: 16

Views: 10959

Answers (2)

Andrew Theken
Andrew Theken

Reputation: 3480

[unowned self] is dangerous. What this does is to tell the runtime 'Assume self has not been released, don't worry about checking.' If self does get released in the meantime, your application will SEGFAULT.

In this case, { [weak self] in self?.someInstanceMethod($0) } will break the reference cycle, and turns into a no-op if self is released.

[weak self] is always safe, while [unowned self] can introduce app crashes if you modify other areas of your code (like view hierarchy, for example)...

Upvotes: 21

rintaro
rintaro

Reputation: 51911

Instead of defining weak reference to the closure, you should use "Capture List" in the closure.

segmentedControl3.indexChangeBlock = { [unowned self] in self.someInstanceMethod($0) }

As far as I know, this is the only way to avoid strong reference cycles.

Upvotes: 9

Related Questions