Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Realm: the right way to make add,update,remove operations from background thread and get results on the main thread

I am using Realm for my app, i want to be able to query results on a background thread and receive them on the main thread. What is the best way to achieve this? and what is the best practice to use realm (having different method for main thread and background? and in main using a static instance of realm across the app? maybe another good way?)

I've read and saw this options are available: - parsing the realm object to my own object and return them (kind of a copy of the results). - returning a the key of the object and querying again from main thread.

Thanks for any help anyone can give me, i really think realm has great potential but there is a lack of good tutorials and best practices.

like image 530
gal.orlanczyk Avatar asked Jan 19 '16 15:01

gal.orlanczyk


1 Answers

First, since Realm is fast enough in most cases, you do not need to run a query in the background.

So the basic strategy is; update in background, fetch in the main thread.

The most general way is to take advantage of the feature of the live update. RLMResults and Results have live update. You can hold RLMResults/Results instances by query. Then you'll make any changes in background thread, the changes are notified and reflected automatically when committed.

// Hold RLMResults for the data source
self.array = [[DemoObject allObjects] sortedResultsUsingProperty:@"date" ascending:YES];

 

// Reload table view when changed by other threads
__weak typeof(self) weakSelf = self;
self.notification = [RLMRealm.defaultRealm addNotificationBlock:^(NSString *note, RLMRealm *realm) {
    [weakSelf.tableView reloadData];
}];

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // RLMResults is updated automatically
    return self.array.count;
}

 

// Update in background 
- (void)backgroundAdd
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // Import many items in a background thread
    dispatch_async(queue, ^{
        // Get new realm and table since we are in a new thread
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm beginWriteTransaction];
        for (NSInteger index = 0; index < 5; index++) {
            // Add row via dictionary. Order is ignored.
            [DemoObject createInRealm:realm withValue:@{@"title": [self randomString],
                                                         @"date": [self randomDate]}];
        }
        [realm commitWriteTransaction];
    });
}

For more details, you can see the table view example in Realm's repo.

If a few cases that Realm doesn't fast enough when fetch on the main thread, you can fetch in background thread. Then aggregate an array of primary keys. Then pass the array and re-fetch on the main thread using the primary keys.

FYI: We are working to add support for running queries asynchronously https://github.com/realm/realm-cocoa/pull/2842 If this feature will be released, you don't need to aggregate primary keys and re-fetch.

like image 113
kishikawa katsumi Avatar answered Oct 02 '22 20:10

kishikawa katsumi