How to use realm.addNotificationBlock?
You can check the class reference to implement the notification handler that catch the changes in the RLMRealm: http://realm.io/docs/cocoa/0.80.0/api/Classes/RLMRealm.html
In this issue you have a test case (non main thread) using the addNotificationBlock.
I hope this may help you.
UPDATE
Check also the examples: RealmTableViewExample
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupUI];
// Set realm notification block
__weak typeof(self) weakSelf = self;
self.notification = [RLMRealm.defaultRealm addNotificationBlock:^(NSString *note, RLMRealm *realm) {
[weakSelf reloadData];
}];
[self reloadData];
}
- (void)reloadData
{
self.array = [[DemoObject allObjects] arraySortedByProperty:@"date" ascending:YES];
[self.tableView reloadData];
}
There is no method addNotificationBlock in Realm. Where is it?
3.0.0 Release notes (2017-10-16)
Breaking Changes
Old API New API
NotificationToken.stop() NotificationToken.invalidate()
-[RLMNotificationToken stop] -[RLMNotificationToken invalidate]
RealmCollection.addNotificationBlock(:) RealmCollection.observe(:)
Try observe
?
How to use Realm notifications
Make notificationToken
an ivar:
var notificationToken: NotificationToken?
deinit{
//In latest Realm versions you just need to use this one-liner
notificationToken?.stop()
/* Previously, it was needed to do this way
let realm = Realm()
if let notificationToken = notificationToken{
realm.removeNotification(notificationToken)
}
*/
}
override func viewDidLoad() {
super.viewDidLoad()
let realm = Realm()
notificationToken = realm.addNotificationBlock { [unowned self] note, realm in
self.tableView.reloadData()
}
...
}
Add Notification to Array of Realm Results
I would go like this, looping through the array as you suggested:
var objectsBySection = [Results<DemoObject>]()
// Fill the objectsBySection array like in your example
...
for (index, objects) in objectsBySection.enumerated() {
registerNotifications(for: objects, in: index)
}
where the registerNotifications(for:in:)
method is defined like this:
func registerNotifications(for results: Results<DemoObject>, in section:Int) {
let notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }
switch changes {
...
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the UITableView
tableView.beginUpdates()
tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: section) }), with: .automatic)
tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: section)}), with: .automatic)
tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: section) }), with: .automatic)
tableView.endUpdates()
break
...
}
}
notificationTokens.append(notificationToken)
}
We assume var notificationTokens
is defined at the class level.
Now, you mentioned that new sections could be added at any time, so let's deal with that too. So we add the plain old non-fine grained notification block and we check if there are new sections added.
notificationToken = realm.addNotificationBlock { [unowned self] note, realm in
// Let's see what the section list looks like now
let sections = Set(realm.objects(DemoObject.self).value(forKey: "sectionTitle") as! [String])
if !Set(sectionTitles).isSuperset(of: sections) {
sectionTitles = Array(sections)
self.tableView.reloadData()
}
}
So, in my simplistic approach, it reloads everything only if new sections are added. If you want to benefit from the nice insert animations you could check instead what sections were added, insert them one by one in the table and then add the new objects to them.
Note: My method to check if sections were added is quite intensive, basically it iterates through all the objects in the DB, so you may want to check it with a realistic load in your app. Unfortunately, until Realm would permit distinct
or group by
queries this is the only way I could imagine to solve this issue.
Realm addNotificationBlock returning error
An untranslated std::exception
is never supposed to make it out of Realm, so that part is a bug.
If you can consistently reproduce the issue, you can set an exception breakpoint in Xcode to break at the point where the error is actually occurring and hopefully find out what's wrong that way.
Testing code which uses Realm addNotificationBlock
You can use expectation(description:)
and waitForExpectations(timeout:handler:)
to test async methods as follows.
func test() {
let q = DispatchQueue(label: "Q")
q.async {
let realm = try! Realm()
try! realm.write {
realm.add(TestObj())
}
}
let e = expectation(description: "Notification fired")
let realm = try! Realm()
let token = realm.addNotificationBlock { (notification, realm) in
print("notification block")
e.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
token.stop()
}
Related Topics
Custom Sequence for Swift Dictionary
How to Get the Correct Current Time in iOS
Xcode 6 Project Crashing After Segue on iOS 7.1
Changing the Shape of a Uiview Border
How to Convert This Opengl Pointer Math to Swift
iOS Swift 2 Record Video Avcapturesession
Uitapgesturerecognizer Sender Is the Gesture, Not the UI Object
iOS with Parse. Pfuser.Currentuser() Not Getting Cached. Returns Nil After App Restart
How to Auto Call an @Ibaction Function
How to Add Custom Data to Marker (Google Maps API Swift)
How to Create a Rounded Rectangle Label in Xcode 7 and Swift 2
Cannot Set Color of Button's Label Inside Menu in Swiftui
Load Large 3D Object .Scn File in Arscnview Aspect Fit in to the Screen Arkit Swift iOS
Transition Delegate for Uitabbarcontroller Animation
Different Cell in Tableview Swift 3
What Is Correct Way to Notify View Controller from Appdelegate