6rod9
6rod9

Reputation: 1457

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 ??

Upvotes: 3

Views: 796

Answers (2)

6rod9
6rod9

Reputation: 1457

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")

Upvotes: 0

Jerry Krinock
Jerry Krinock

Reputation: 5020

You could observe NSManagedObjectContextObjectsDidChange. This may be somewhat overkill, because it sends a notification when any change occurs to any objects(s). But I've used it without any noticeable performance hit. Here is the Apple documentation.

The main drawback of NSManagedObjectContextObjectsDidChange is that it does not give you the changed keys or values. If you need that, realize that creating observers on all properties may not be as onerous as you think. It can be done in a single loop, iterating over NSEntityDescription.properties or one of the other four similar properties listed at the bottom of its documentation.

Upvotes: 0

Related Questions