Search code examples
iosobjective-ccore-datansmanagedobjectcontext

Create the managedObjectContext for background queue for already created UIManagedDocument


How to create a managedObjectContext for already created UIManagedDocument and associate it with a global dispatch queue? Or what is the proper way of creating the managedObjectContext.

Info: I'm dealing with my managedObjectContext in the most primitive way, just via creating it together with managedDocument _managedDocument = [[UIManagedDocument alloc] initWithFileURL:url];

However this will associate managedObjectContext with the main queue, which I would like to avoid, and associate it with this queue.

_backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

What is the proper way of doing it?


Solution

  • Alright, solved it, the exact answer:

    Core Data requires that each queue operates its own separate managedObjectContext, which is created on the queue to which it will belong. As data is fetched on this managedObjectContext, it will be merged into the main queue’s Managed Object Context. To create the background managedObjectContext, give it the same Persistent Store Coordinator as the main queue’s managedObjectContext. Using this notification, when the background Managed Object Context saves, the changes are sent to the main queue and merged in.

    Then good way to perform fetching, is to do it inside performBlock:, to ensure you are fetching on the right queue.

    [_backgroundManagedObjectContext performBlock:^{
           // fetch here
        }];
    

    Complete listing:

    @implementation databaseManager {
        UIManagedDocument* _databaseManagedDocument;
    
        NSManagedObjectContext* _backgroundManagedObjectContext;
        dispatch_queue_t _backgroundContentFetchingQueue;
    
    }
    
    - (id)init
    {
        self = [super init];
        if (self) {
    
            NSURL* url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
            url = [url URLByAppendingPathComponent:@"database"];
    
            _databaseManagedDocument = [[UIManagedDocument alloc] initWithFileURL:url];
            _backgroundContentFetchingQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    
            [self openManagedDocument];  
        }
    
        return self;
    }
    
    - (void)initializeBackgroundManagedObjectContext
    {
        dispatch_async(_backgroundContentFetchingQueue, ^{
    
            NSPersistentStoreCoordinator *coordinator = _databaseManagedDocument.managedObjectContext.persistentStoreCoordinator;
            if (!coordinator) {
                // Error if we don't have a coordinator.
                return;
            }
    
            // Create the Background Managed Object Context
            _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
            [_backgroundManagedObjectContext setPersistentStoreCoordinator:coordinator];
            [_backgroundManagedObjectContext setUndoManager:nil];
    
            // Notify the main queue of changes the background queue makes
            [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
                                                              object:_backgroundManagedObjectContext
                                                               queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
                                                                   dispatch_async(dispatch_get_main_queue(), ^{
                                                                       [_databaseManagedDocument.managedObjectContext mergeChangesFromContextDidSaveNotification:note];
                                                                   });
                                                               }];
        });
    
    }
    
    - (void)openManagedDocument
    {
        if (!([[NSFileManager defaultManager] fileExistsAtPath:[_databaseManagedDocument.fileURL path]])){
            [_databaseManagedDocument saveToURL:_databaseManagedDocument.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
                if (success) {
                    [self initializeBackgroundManagedObjectContext];
                } else NSLog(@"Database document creation error");
            }];
        } else if (_databaseManagedDocument.documentState == UIDocumentStateClosed) {
            [_databaseManagedDocument openWithCompletionHandler:^(BOOL success){
                if (success) {
                    [self initializeBackgroundManagedObjectContext];
                } else NSLog(@"Database document opening error");
            }];
    
        } else if (_databaseManagedDocument.documentState == UIDocumentStateNormal) {
    
            [self initializeBackgroundManagedObjectContext];
        }
    }
    
    - (void)dealloc
    {
        dispatch_release(_backgroundContentFetchingQueue);
    }
    
    @end
    

    Hope I haven't missed anything. The original post here : POST