Reputation: 1021
The title is a bit confusing, but it pretty much says it all. I want to have a property observer on a property of a property:
class A {
var b: B
init() {
b = B()
}
func foo() { }
}
class B {
var c = 0
fun bar() { }
}
var a = A()
In this example to illustrate what I want, I want a.foo()
to be called whenever a.b.c
is set. If I wanted to call a.b.bar()
instead, this could easily be done by changing
var c = 0
to
var c = 0 {
didSet {
bar()
}
}
However, what I want to be done has no easy way to be implemented. This is the only way of getting to behave as I want that I can think of:
class A {
var b: B {
didSet {
b.a = self
}
}
init() {
b = B()
b.a = self
}
func foo() { }
}
class B {
weak var a: A?
var c = 0 {
didSet {
a?.foo()
}
}
}
This just seems like a very messy solution that seems like it should have a better one. Thanks for any help.
Upvotes: 3
Views: 151
Reputation: 93151
The cleanest solution is to make A
derive from NSObject
so it can use Key Value Observing:
class A: NSObject {
var b: B
override init() {
b = B()
super.init()
self.addObserver(self, forKeyPath: "b.c", options: [.New], context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "b.c" {
foo()
}
}
func foo() {
print("b.c. has changed")
}
}
class B: SKSpriteNode {
// Remember to mark it dynamic here
dynamic var c = 0
func bar() { }
}
var a = A()
a.b.c = 42 // will trigger a.foo()
If you don't want that, use the delegate
pattern:
protocol BDelegate {
func foo()
}
class A: BDelegate {
var b: B
init() {
b = B()
b.delegate = self
}
func foo() {
print("b.c. has changed")
}
}
class B: SKSpriteNode {
var delegate: BDelegate?
var c = 0 {
didSet {
delegate?.foo()
}
}
func bar() { }
}
var a = A()
a.b.c = 42 // will trigger a.foo()
Upvotes: 1