Search code examples
iosswiftmvvmreactive-programmingreactive-cocoa

Observing object properties with ReactiveCocoa 4 in Swift


As a preface, this might be an incredibly simple and/or ignorant question.

In ReactiveCocoa 2.x, we were able to use RACObserve and RAC to observe properties of an object. From the documentation I can find in Reactive 3 and 4, we now use PropertyType to observe changes to an object property. I have so far been unsuccessful in being able to observe any property change when using MutableProperty or DynamicProperty.

class TempObject {
  var property: String
}

let tempObject = TempObject()
let propertyObserver: MutableProperty<String> = MutableProperty(tempObject.property)

From what I understand, I should be able to use propertyObserver to view changes to tempObject.property. I tried adding a map function to the signal producer from propertyObserver to see if it was firing, but don't see anything when updating tempObject.property. Again, could be a trivial thing that I am missing, thanks so much.

Edit

NachoSoto nailed it - I needed to make my property KVO compliant. I also ended doing this:

let tempObjectSignal: MutableProperty<TempObject> = MutableProperty(tempObject)
let propertyObserver: MutableProperty<String> <~ tempObjectSignal.producer.map({ $0.property })

And whenever tempObject.property is updated I make sure to call

tempObjectSignal.value = tempObject

This fires off all the necessary signals. I don't know if this breaks any best practices, though. Let me know what you think!


Solution

  • MutableProperty(value) creates a mutable property but only with value that as the initial value.

    What you want to use is DynamicProperty, which will use the Objective-C runtime and KVO to detect changes to an object's property:

    let property = DynamicProperty(tempObject, "property")
    

    For that reason, however, you need to make sure that the property you want to observe is part of the Objective-C runtime, by making the class a subclass of NSObject, and by either using the dynamic keyword:

    class TempObject: NSObject {
        dynamic var property: String
    }
    

    Or using @objc to ensure that it gets exported to the runtime:

    class TempObject: NSObject {
        @objc var property: String
    }