Search code examples
iosobjective-crealmios-multithreading

Realm - Batch update RLMResults on background thread


I have RLMResults that I need to iterate over, do a potentially "long-running" download task, (long enough it shouldn't be on the main thread), and update each object with the result of this download. The latest iteration on what I've attempted (after scouring the docs for an answer) is something like this, although this obviously doesn't work as intended, but its a starting point for demonstration purposes:

RLMResults *objectsToSaveImagesFor = [self allObjectsToSaveImagesFor];
for (Object *object in objectsToSaveImagesFor) {
    RLMThreadSafeReference *objectRef = [RLMThreadSafeReference referenceWithThreadConfined:object];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        RLMRealm *realm = [RLMRealm realmWithConfiguration:self.realm.configuration error:nil];

        Object *threadSafeObject = [realm resolveThreadSafeReference:objectRef];

        BOOL success = [self downloadImageForObject:threadSafeObject];

        [realm transactionWithBlock:^{
            threadSafeObject.imageSaved = success;
        }];
    });
}

I've tried about a dozen iterations on this and can't manage to figure out the canonical Realm way to do what I'd like to do, which is download a large number of images (in the thousands) and update each of my Realm objects with the result of the download on a background thread.


Solution

  • Rather than create and resolve a thread-safe reference for each object in the RLMResults, just do it once:

    RLMResults *objectsToSaveImagesFor = [self allObjectsToSaveImagesFor];
    RLMThreadSafeReference *objectsRef = [RLMThreadSafeReference referenceWithThreadConfined:objectsToSaveImagesFor];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        RLMRealm *realm = [RLMRealm realmWithConfiguration:self.realm.configuration error:nil];
        RLMResults *objectsToSaveImagesFor2 = [realm resolveThreadSafeReference:objectsRef];
        for (Object *object in objectsToSaveImagesFor2) {
          BOOL success = [self downloadImageForObject:threadSafeObject];
          [realm transactionWithBlock:^{
            object.imageSaved = success;
          }];
        }
    });