16

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?

zisoft
  • 22,770
  • 10
  • 62
  • 73
WildCat
  • 1,961
  • 6
  • 24
  • 35
  • possible duplicate of [Make self weak in methods in Swift](http://stackoverflow.com/questions/25613783/make-self-weak-in-methods-in-swift) – user102008 Jan 09 '15 at 03:39

2 Answers2

21

[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)...

Andrew Theken
  • 3,392
  • 1
  • 31
  • 54
  • 1
    The HMSegmentedControl is owned by the ExampleVC, so you will never have self to be nil. And as Apple say: use unowned whenever it is possible. – Dam Nov 07 '16 at 16:51
  • 1
    Unowned is still fundamentally unsafe. I know it's good to follow what Apple recommends, and this is probably for performance reasons, but I stand by my recommendation, for the reasons I outlined. – Andrew Theken Nov 07 '16 at 16:57
  • 1
    I agree with you, weak will always be safe. The point was just unowned is not just assume it is not release, it is more, as the developer, I say it will never be nil. But I also agree with you I prefer to be 100% sure than let someone say it is safe, jump. – Dam Nov 08 '16 at 09:11
9

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.

rintaro
  • 51,423
  • 14
  • 131
  • 139
  • 8
    `[weak self]` will break the reference cycle and is generally less prone to breakage when code gets refactored or view hierarchies are reorganized. – Andrew Theken Oct 30 '15 at 19:17