I need an observable property on certain view controllers in my application, I'm trying to standardize this through a protocol.
protocol MyProtocol: UIViewController {
dynamic var observeMe: Bool { get set }
}
But when trying to observe the property like so:
let viewController = UIViewController()
if let observableViewController = viewController as? MyProtocol {
observableViewController.observe(\.observeMe, options: [.old, .new], changeHandler: { object, change in
// Do something
})
}
Xcode throws the compiler error:
"Member 'observe' cannot be used on value of protocol type 'MyProtocol'; use a generic constraint instead"
You can declare a function and apply the generic constraint to it.
In Swift 5.7 you can simply do:
func observeViewController(_ vc: some MyProtocol) {
vc.observe(\.observeMe, options: [.old, .new], changeHandler: { object, change in
})
}
Then you can call it:
let viewController = UIViewController()
if let observableViewController = viewController as? MyProtocol {
observeViewController(viewController)
}
Prior to Swift 5.7, some MyProtocol is not supported and you need to use type erasure:
class AnyMyProtocol: MyProtocol & UIViewController {
var observeMe: Bool
private var base: MyProtocol
init(_ base: MyProtocol) {
self.base = base
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
func observeViewController(_ vc: MyProtocol) {
vc.observe(\.observeMe, options: [.old, .new], changeHandler: { object, change in
})
}
And call it like so:
let viewController = UIViewController()
observeViewController(vc: AnyMyProtocol(base: observableViewController))
By the way, you will receive a warning reading:
Passing reference to non-'@objc dynamic' property 'observeMe' to KVO method 'observe(_:options:changeHandler:)' may lead to unexpected behavior or runtime trap
But in your case you can't declare it as @objc because an @objc protocol can't inherit from a non-protocol type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With