2

In a view controller in my app, I'm reacting to changes to a view's positioning by key-value observing its center property, like this:

class CoordinatingViewController: UIViewController {

    @IBOutlet weak var cardContainerView: CardView!

    override func viewDidLoad() {
         super.viewDidLoad()
         addObserver(self, forKeyPath: "cardContainerView.center", options: [.new], context: nil)
    }
}

This works just fine for now, but since that key path is a string, it can't be checked by the compiler. To mitigate this, I'd like to use Swift 3's #keyPath() syntax, which takes a compiler-checked key path and returns the proper corresponding string. However, when I change that line to use it like this:

addObserver(self, forKeyPath: #keyPath(cardContainerView.center), options: [.new], context: nil)

The compiler gives me 2 errors:

  1. Type 'CardView!' has no member 'center'
  2. Cannot refer to type member 'center' within instance of type 'CardView!'

I don't understand why I'm getting these errors, as center is a documented property of UIView, which CardView inherits from directly, which I can both read and write to outside the #keyPath() statement there. Furthermore, everything appears to work ok when I pass the key path directly as a string, as in my first example, which makes this even more confusing. How can I have the compiler check that key path for me?

Michael Hulet
  • 3,253
  • 1
  • 16
  • 33
  • Try removing the `weak` modifier. I don't know why but it works for me... – Sweeper May 31 '18 at 07:26
  • Interesting! That seems to work for me, too. That being said, I'm timid to remove it, because it was added by Interface Builder. Would removing it cause a retain cycle or have any other side effects? I'm not aware of it being involved in any retain cycles in *my* code, even with the `weak` modifier gone – Michael Hulet May 31 '18 at 07:34

1 Answers1

1

It seems like Swift is not happy about the weak modifier. Remove it and the code will compile. From this, we can see that outlets are recommended to be strong, unless you actually have a retain cycle. See my answer here for how to find retain cycles.

In Swift 4, you will be able to do this, using the new \ key path syntax:

// no problems with "weak"!
let observation = observe(\.cardContainerView.center) { (object, change) in
    ...
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313