Be notified when any of an Object's properties changes value.
There are addNotificationBlock methods on Results and List, which makes reacting to value changes very easy. For observing changes to an Object you got to use KVO, which is somewhat clunky should you not use a 3rd party lib for it.
I think there is a valid use case for adding addNotificationBlock to Object - especially when you are having a view controller that shows the information contained in a single object. For example in a Master-Detail application when you select one item in the master view controller you would have the following screen show all the data of a realm object (should that be how the app works). Now while the user has this screen open reacting to changes of the represented object means to observe each of the properties of that object. (Or the object representing the data in a single table cell, etc.)
I can see a complication in the implementation, which is the case in which the object gets deleted while having an active notification block attached - I think in that case calling the notification block one last time before the object is released with a nil value would suffice to provide means for the app to react to that event.
A view controllers viewDidLoad might look like this to always show live data on screen:
let luvStock = realm.objects(Stock).filter("symbol='LUV'").first!
self.updateUIWithStock(luvStock)
token = luvStock.addNotificationBlock {[weak self]latestStock, error in
guard let `self` = self else {return}
if let latestStock = latestStock {
self.updateUIWithStock(luvStock)
} else {
self.popViewControllerAnimated(true)
}
}
The example will fetch one Stock object from Realm, the update the UI any time any of the values has been updated in the background from the network controller, and finally if for whatever reason the object gets deleted it will just pop back to the previous screen.
This is definitely something we want to do. We've discussed this internally a few times. To go even further, it'd be nice to have all this behind a protocol, to have a consistent change notification API. Something like RealmObservable.
One minor point: addNotificationBlock(_:) currently runs once immediately when calling, making your initial updateUIWithStock(_:) invocation unnecessary. It has this behavior because this pattern is so common.
Actually there is no docs fir that method - I wanted to check if the block is to be called immediately upon creating a Results onject of not and found out that there is no docs. Would be great to add a description what the intended behavior is
Further - today I definitely discovered a recreatable case when the block is not called immediateli will open another issue about that.
Actually there are docs: https://github.com/realm/realm-cocoa/blob/v0.98.6/RealmSwift-swift2.0/Results.swift#L324-L353
That documentation isn't rendered in our API docs due to a bug in jazzy that's since been fixed. The new output should be this: https://github.com/realm/jazzy-integration-specs/blob/master/document_realm_swift/after/docs/Classes/Results.html#L1346-L1374
We'll soon be cutting a new release of Realm (#3433) which will use an updated version of jazzy that includes the fix.
Before you open an issue about a write transaction block not "called immediately", please make sure you read the docs on Seeing Changes From Other Threads as that's often explained past situations in which users thought that changes weren't immediately persisted, but the subtlety of this behavior is easy to misunderstand.
0.98.7 is out, so the API docs have been updated and include the doc discussion for Results.addNotificationBlock(_:).
no threads at all, the notification example I have is pretty simple - I'm not 100% sure if it's a bug or expected behavior but it certainly does not do what the docs say, I created an issue here: https://github.com/realm/realm-cocoa/issues/3435
I'm writing extensions for RxSwift and would also like to see something like this.
Current implementation for results works as expected...
https://gist.github.com/gregpardo/bec8741ac4a53c6362d9188e44f4309e
Was hoping to make an rx_objectForPrimary key method but doesn't look like this is currently possible.
You could do something along the lines of the following (note: not tested at all):
extension Realm {
public func rx_objectForPrimaryKey<T: Object>(type: T.Type, key: AnyObject) -> Observable<T?> {
return self.objects(type)
.filter("%K = %@", self.schema[type.className]!.primaryKeyProperty!.name, key)
.rx_results
.map { $0.first }
}
}
Yes I actually did go with something very similar in the mean time. Thank you! Do you know if there is any performance penalty for something like this or if the queries are similar underneath to fetch from primary key?
Think I'm going to go with yours . Although I added this little guy.
extension Results where T: Object {
public var rx_result: Observable<T?> {
return self.rx_results.map { $0.first }
}
}
Is there anyway to prevent the initial call to the notification block when you add it? I have a case where I add a notification block in viewWillAppear but don't want it to be called. I set the token to nil in viewWillDisappear.
No need to prevent it鈥攜ou can easily distinguish the initial callback from any updates. If you're using Realm Swift, just ignore the Initial enum case. If you're using Realm Objective-C, just ignore the callback where the RLMCollectionChange * parameter is nil.
Ah that makes a lot of sense thanks!
I am confused by this, op is talking about a notification block on a realm object though there is no possibility to do it, i can only put a notification block on Result
Did i miss something?
@tirrorex this ticket is a feature request, there's presently no API to add notification blocks to Realm objects, that can only be done on Realms and Realm Collections.
My bad, didn't see the label, thanks for answering though
@jpsim
I have one more layer of abstractions on top of all realm-objects, where if updateListener will be set, I will instantiate object associated query Results entity (based on primary key filter), and add notificationBlock to it.
So far it has been working great, so are there any drawbacks backing RealmObject with associated query Results entity provided that only object that will have updateListener set will be backed?
@ambientlight sounds like that might work with your case. It's certainly a bit wasteful to create a query for just a single object, but if you don't need to know which properties were modified and want to avoid KVO's uncomfortable API, your approach sounds fine.
This has been added in Realm 2.4.0! Yippee! :)
Most helpful comment
This has been added in Realm 2.4.0! Yippee! :)