Search code examples
iosswiftcore-datareactive-cocoareactive-swift

ReactiveSwift: Observe Managed Object changes with MutableProperty


My project has CoreData database with 1 root context and multiple sub contexts. I have a ViewModel that contains an Item (NSManagedObject). When I changes something in an Item the persistence is made in the root context and then automatically merged into all sub-contexts.

I want to replace the NSFetchedResultsController with ReactiveSwift Signals / Properties, to observe changes in the item object.

ViewModel:

var itemProperty: MutableProperty<Item> = MutableProperty(contextItem)

ViewController:

self.viewModel.itemProperty.signal.observeValues{ (item: Item) in
     let newName = item.name
     print("name: \(newName!)" 
 }

After I change the item's name somewhere else, the changes are propagated to the ViewModel sub-context (the NSFetchedResultsController gets notified), BUT the signal never pushes a new item event.

Maybe because the NSManagedObject reference never changes? I know I can observe changes to specific properties in an object with producer(forKeyPath: "propertyKeyPath" ), but I don't want to observe just one specific property of the item, I want to observe ALL changes.

Is there a way to observe ANY change in all the object's properties ??


Solution

  • So apparently after a little research I found out ReactiveCocoa it's not so well prepared to work with Core Data. It is not possible to receive NSManagedObject updates with just ReactiveCocoa/ReactiveSwift.

    One option could be updating the ItemProperty with each update from a NSFetchedResultsController and trigger a new event on the property's associated signal:

    var entityProperty: MutableProperty<MyEntity>
    
    override func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
    {
        entityProperty.value = anObject as! MyEntity
    }
    

    Another option could be to get a signal for updates on specific properties in my entity:

    var myEntity: MyEntity
    
    // ReactiveObjectiveC
    myEntity.rac_values(forKeyPath: "name", observer: self)
    
    // ReactiveSwift
    myEntity.reactive.signal(forKeyPath: "name")