2013-04-04 2 views
2

У меня есть одноэлементный класс, который сохраняет объекты JSON в базу данных CoreData в фоновом режиме с помощью очередей GCD (Grand Central Dispatch). Это работает отлично в большинстве случаев, но на устройствах iPad 2 и iPad Mini у меня возникают некоторые проблемы с замораживанием процесса.Сохранение CoreData на фоне зависания фоновой очереди GCD на iPad Mini

Моя установка довольно проста. У меня есть фоновая диспетчерская очередь (backgroundQueue), которая запускается серийно, и у меня есть отдельный экземпляр NSManagedObjectContext для фоновой очереди. Когда я хочу что-то сохранить в базе данных, я вызываю метод, который начинает процесс сохранения, и в этом методе я использую dispatch_async для вызова моей логики сохранения в фоновом потоке.

После того, как все логические операции обработки выполнены, я сохраняю фоновый MOC и использую NSManagedObjectContextDidSaveNotification для объединения изменений из фонового MOC в основной поток MOC. Фоновый поток ждет завершения этого процесса, и как только это будет сделано, он запустит следующий блок в очереди, если таковой будет. Ниже мой код.

dispatch_queue_t backgroundQueue; 

- (id)init 
{ 
    if (self = [super init]) 
    { 
     // init the background queue 
     backgroundQueue = dispatch_queue_create(VS_CORE_DATA_MANAGER_BACKGROUND_QUEUE_NAME, DISPATCH_QUEUE_SERIAL); 
    } 
    return self; 
} 

- (void)saveJsonObjects:(NSDictionary *)jsonDict 
      objectMapping:(VS_ObjectMapping *)objectMapping 
        class:(__unsafe_unretained Class)managedObjectClass 
      completion:(void (^)(NSArray *objects, NSError *error))completion 
{ 
    [VS_Log logDebug:@"**** Queue Save JSON Objects for Class: %@", managedObjectClass]; 

    // process in the background queue 
    dispatch_async(backgroundQueue, ^(void) 
    { 
     [VS_Log logDebug:@"**** Dispatch Save JSON Objects for Class: %@", managedObjectClass]; 

     // create a new process object and add it to the dictionary 
     currentRequest = [[VS_CoreDataRequest alloc] init]; 

     // set the thead name 
     NSThread *currentThread = [NSThread currentThread]; 
     [currentThread setName:VS_CORE_DATA_MANAGER_BACKGROUND_THREAD_NAME]; 

     // if there is not already a background context, then create one 
     if (!_backgroundQueueManagedObjectContext) 
     { 
      NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
      if (coordinator != nil) 
      { 
       // create the background queue 
       _backgroundQueueManagedObjectContext = [[NSManagedObjectContext alloc] init]; 
       [_backgroundQueueManagedObjectContext setPersistentStoreCoordinator:coordinator]; 
       [_backgroundQueueManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
       _backgroundQueueManagedObjectContext.undoManager = nil; 

       // listen for the merge changes from context did save notification on the background queue 
       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChangesFromBackground:) name:NSManagedObjectContextDidSaveNotification object:_backgroundQueueManagedObjectContext]; 
      } 
     } 

     // save the JSON dictionary 
     NSArray *objects = [self saveJSON:jsonDict objectMapping:objectMapping class:managedObjectClass managedObjectContext:_backgroundQueueManagedObjectContext level:0]; 

     // save the objects so we can access them later to be re-fetched and returned on the main thread 
     if (objects.count > 0) 
      [currentRequest.objects addObjectsFromArray:objects]; 

     // save the object IDs and the completion block to global variables so we can access them after the save 
     if (completion) 
      currentRequest.completionBlock = completion; 

     [VS_Log logDebug:@"**** Save MOC for Class: %@", managedObjectClass]; 

     // save all changes object context 
     [self saveManagedObjectContext]; 
    }); 
} 

- (void)mergeChangesFromBackground:(NSNotification *)notification 
{ 
    [VS_Log logDebug:@"**** Merge Changes From Background"]; 

    // save the current request to a local var since we're about to be processing it on the main thread 
    __block VS_CoreDataRequest *request = (VS_CoreDataRequest *)[currentRequest copy]; 
    __block NSNotification *bNotification = (NSNotification *)[notification copy]; 

    // clear out the request 
    currentRequest = nil; 

    dispatch_sync(dispatch_get_main_queue(), ^(void) 
    { 
     [VS_Log logDebug:@"**** Start Merge Changes On Main Thread"]; 

     // merge changes to the primary context, and wait for the action to complete on the main thread 
     [_managedObjectContext mergeChangesFromContextDidSaveNotification:bNotification]; 

     NSMutableArray *objects = [[NSMutableArray alloc] init]; 

     // iterate through the updated objects and find them in the main thread MOC 
     for (NSManagedObject *object in request.objects) 
     { 
      NSError *error; 
      NSManagedObject *obj = [[self managedObjectContext] existingObjectWithID:object.objectID error:&error]; 
      if (error) 
       [self logError:error]; 

      if (obj) 
       [objects addObject:obj]; 
     } 

     // call the completion block 
     if (request.completionBlock) 
     { 
      void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
      saveCompletionBlock(objects, nil); 
     } 

     [VS_Log logDebug:@"**** Complete Merge Changes On Main Thread"]; 

     // clear the request 
     request = nil; 
    }); 

    [VS_Log logDebug:@"**** Complete Merge Changes From Background"]; 
} 

Когда проблема возникает все, кажется, бежит хорошо, и он попадает в mergeChangesFromBackground: метод, но dispatch_async() не вызывается.

Как я уже упоминал выше, код в большинстве случаев отлично работает. Только когда у него проблемы с запуском, я тестирую iPad или iPad Mini и сохраняю большие объекты.

Есть ли у кого-нибудь идеи, почему это происходит?

Благодаря

** EDIT **

С момента написания этого я узнал о вложенном NSManagedObjectContexts. Я изменил свой код, чтобы использовать его, и, похоже, он работает хорошо. Однако у меня все еще есть те же проблемы. Мысли? Кроме того, какие-либо комментарии относительно вложенных MOC?

- (void)saveJsonObjects:(NSDictionary *)jsonDict 
      objectMapping:(VS_ObjectMapping *)objectMapping 
        class:(__unsafe_unretained Class)managedObjectClass 
      completion:(void (^)(NSArray *objects, NSError *error))completion 
{ 
    // process in the background queue 
    dispatch_async(backgroundQueue, ^(void) 
    { 
     // create a new process object and add it to the dictionary 
     __block VS_CoreDataRequest *currentRequest = [[VS_CoreDataRequest alloc] init]; 

     // set the thead name 
     NSThread *currentThread = [NSThread currentThread]; 
     [currentThread setName:VS_CORE_DATA_MANAGER_BACKGROUND_THREAD_NAME]; 

     // if there is not already a background context, then create one 
     if (!_backgroundQueueManagedObjectContext) 
     { 
      NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
      if (coordinator != nil) 
      { 
       // create the background queue 
       _backgroundQueueManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
       [_backgroundQueueManagedObjectContext setParentContext:[self managedObjectContext]]; 
       [_backgroundQueueManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
       _backgroundQueueManagedObjectContext.undoManager = nil; 
      } 
     } 

     // save the JSON dictionary starting at the upper most level of the key path 
     NSArray *objects = [self saveJSON:jsonDict objectMapping:objectMapping class:managedObjectClass managedObjectContext:_backgroundQueueManagedObjectContext level:0]; 

     // if no objects were processed, then return with an error 
     if (!objects || objects.count == 0) 
     { 
      currentRequest = nil; 

      // dispatch the completion block 
      dispatch_async(dispatch_get_main_queue(), ^(void) 
      { 
       NSError *error = [self createErrorWithErrorCode:100 description:@"No objects were found for the object mapping"]; 
       [self logMessage:error.debugDescription]; 
       completion(nil, error); 
      }); 
     } 

     // save the objects so we can access them later to be re-fetched and returned on the main thread 
     if (objects.count > 0) 
      [currentRequest.objects addObjectsFromArray:objects]; 

     // save the object IDs and the completion block to global variables so we can access them after the save 
     if (completion) 
      currentRequest.completionBlock = completion; 

     // save all changes object context 
     NSError *error = nil; 
     [_backgroundQueueManagedObjectContext save:&error]; 
     if (error) 
      [VS_Log logError:error.localizedDescription]; 

     dispatch_sync(dispatch_get_main_queue(), ^(void) 
     { 
      NSMutableArray *objects = [[NSMutableArray alloc] init]; 

      // iterate through the updated objects and find them in the main thread MOC 
      for (NSManagedObject *object in currentRequest.objects) 
      { 
       NSError *error; 
       NSManagedObject *obj = [[self managedObjectContext] existingObjectWithID:object.objectID error:&error]; 
       if (error) 
        [self logError:error]; 

       if (obj) 
        [objects addObject:obj]; 
      } 

      // call the completion block 
      if (currentRequest.completionBlock) 
      { 
       void (^saveCompletionBlock)(NSArray *, NSError *) = currentRequest.completionBlock; 
       saveCompletionBlock(objects, nil); 
      } 
     }); 

     // clear out the request 
     currentRequest = nil; 
    }); 
} 

** EDIT **

Привет всем,

я сначала хотел бы поблагодарить всех за этот вход на это, так как это то, что привело меня к нахождению решения для моей проблемы , Короче говоря, я полностью избавился от использования GCD и пользовательской фоновой очереди, вместо этого теперь я использую вложенные контексты и метод «executeBlock» для выполнения всех изменений в фоновом потоке. Это отлично работает, и я поднял свою проблему.

Однако у меня теперь есть новая ошибка. Всякий раз, когда я запускаю свое приложение в первый раз, всякий раз, когда я пытаюсь сохранить объект с дочерними объектными отношениями, я получаю следующее исключение.

-_referenceData64 только для абстрактного класса. Определить - [NSTemporaryObjectID_default _referenceData64]!

Ниже мой новый код.

- (void)saveJsonObjects:(NSDictionary *)jsonDict 
      objectMapping:(VS_ObjectMapping *)objectMapping 
        class:(__unsafe_unretained Class)managedObjectClass 
      completion:(void (^)(NSArray *objects, NSError *error))completion 
{ 
    [_backgroundManagedObjectContext performBlock:^(void) 
    { 
     // create a new process object and add it to the dictionary 
     VS_CoreDataRequest *currentRequest = [[VS_CoreDataRequest alloc] init]; 
     currentRequest.managedObjectClass = managedObjectClass; 

     // save the JSON dictionary starting at the upper most level of the key path 
     NSArray *objects = [self saveJSON:jsonDict objectMapping:objectMapping class:managedObjectClass managedObjectContext:_backgroundManagedObjectContext level:0]; 

     if (objects.count == 0) 
     { 
      currentRequest.error = [self createErrorWithErrorCode:100 description:@"No objects were found for the object mapping"]; 
      [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
     } 
     else 
     { 
      // save the objects so we can access them later to be re-fetched and returned on the main thread 
      [currentRequest.objects addObjectsFromArray:objects]; 

      // save the object IDs and the completion block to global variables so we can access them after the save 
      currentRequest.completionBlock = completion; 

      [_backgroundManagedObjectContext lock]; 

      @try 
      { 
       [_backgroundManagedObjectContext processPendingChanges]; 
       [_backgroundManagedObjectContext save:nil]; 
      } 
      @catch (NSException *exception) 
      { 
       currentRequest.error = [self createErrorWithErrorCode:100 description:exception.reason]; 
      } 

      [_backgroundManagedObjectContext unlock]; 

      // complete the process on the main thread 
      if (currentRequest.error) 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
      else 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidSucceed:) withObject:currentRequest waitUntilDone:NO]; 

      // clear out the request 
      currentRequest = nil; 
     } 
    }]; 
} 

- (void)backgroundSaveProcessDidFail:(VS_CoreDataRequest *)request 
{ 
    if (request.error) 
     [self logError:request.error]; 

    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(nil, request.error); 
    } 
} 

- (void)backgroundSaveProcessDidSucceed:(VS_CoreDataRequest *)request 
{ 
    // get objects from main thread 
    NSArray *objects = nil; 
    if (request.objects.count > 0) 
    { 
     NSFetchRequest *fetchReq = [NSFetchRequest fetchRequestWithEntityName:[NSString stringWithFormat:@"%@", request.managedObjectClass]]; 
     fetchReq.predicate = [NSPredicate predicateWithFormat:@"self IN %@", request.objects]; 
     objects = [self executeFetchRequest:fetchReq]; 
    } 

    // call the completion block 
    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(objects, nil); 
    } 
} 

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (_managedObjectContext != nil) { 
     return _managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) 
    { 
     // create the MOC for the backgroumd thread 
     _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [_backgroundManagedObjectContext setPersistentStoreCoordinator:coordinator]; 
     [_backgroundManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
     _backgroundManagedObjectContext.undoManager = nil; 

     // create the MOC for the main thread 
     _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     [_managedObjectContext setParentContext:_backgroundManagedObjectContext]; 
     [_managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
    } 

    return _managedObjectContext; 
} 

Есть ли у вас какие-либо идеи, почему происходит этот сбой?

+0

После редактирования вы будете дополнительно сохранять (в mainManagedObjectContext), чтобы ваши изменения сохранялись в хранилище. Это означает операцию ввода-вывода в основном потоке, и вы можете избежать этого. –

+0

Вложенные контексты являются удивительными. Одна вещь сразу привлекла мое внимание. Вы должны создать контекст типа private queue в своем основном потоке, так как вам не разрешено касаться вашего основного контекста ни в каком другом потоке, кроме основного потока. Другими словами, установка [self managedObjectContext] в качестве родительского контекста в фоновом потоке недействительна. – svena

+0

Кроме того, вы можете коснуться частного контекста только в блоке, отправленном как аргумент метода [privateContext performBlock:]. – svena

ответ

0

Прежде всего я хотел бы поблагодарить всех за этот вклад, поскольку именно это привело меня к поиску решения моей проблемы. Короче говоря, я полностью избавился от использования GCD и пользовательской фоновой очереди, вместо этого теперь я использую вложенные контексты и метод «executeBlock» для выполнения всех изменений в фоновом потоке. Это отлично работает, и я поднял свою проблему.

Однако у меня теперь есть новая ошибка. Всякий раз, когда я запускаю свое приложение в первый раз, всякий раз, когда я пытаюсь сохранить объект с дочерними объектными отношениями, я получаю следующее исключение.

-_referenceData64 только для абстрактного класса. Определить - [NSTemporaryObjectID_default _referenceData64]!

Ниже мой новый код.

- (void)saveJsonObjects:(NSDictionary *)jsonDict 
      objectMapping:(VS_ObjectMapping *)objectMapping 
        class:(__unsafe_unretained Class)managedObjectClass 
      completion:(void (^)(NSArray *objects, NSError *error))completion 
{ 
    [_backgroundManagedObjectContext performBlock:^(void) 
    { 
     // create a new process object and add it to the dictionary 
     VS_CoreDataRequest *currentRequest = [[VS_CoreDataRequest alloc] init]; 
     currentRequest.managedObjectClass = managedObjectClass; 

     // save the JSON dictionary starting at the upper most level of the key path 
     NSArray *objects = [self saveJSON:jsonDict objectMapping:objectMapping class:managedObjectClass managedObjectContext:_backgroundManagedObjectContext level:0]; 

     if (objects.count == 0) 
     { 
      currentRequest.error = [self createErrorWithErrorCode:100 description:@"No objects were found for the object mapping"]; 
      [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
     } 
     else 
     { 
      // save the objects so we can access them later to be re-fetched and returned on the main thread 
      [currentRequest.objects addObjectsFromArray:objects]; 

      // save the object IDs and the completion block to global variables so we can access them after the save 
      currentRequest.completionBlock = completion; 

      [_backgroundManagedObjectContext lock]; 

      @try 
      { 
       [_backgroundManagedObjectContext processPendingChanges]; 
       [_backgroundManagedObjectContext save:nil]; 
      } 
      @catch (NSException *exception) 
      { 
       currentRequest.error = [self createErrorWithErrorCode:100 description:exception.reason]; 
      } 

      [_backgroundManagedObjectContext unlock]; 

      // complete the process on the main thread 
      if (currentRequest.error) 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
      else 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidSucceed:) withObject:currentRequest waitUntilDone:NO]; 

      // clear out the request 
      currentRequest = nil; 
     } 
    }]; 
} 

- (void)backgroundSaveProcessDidFail:(VS_CoreDataRequest *)request 
{ 
    if (request.error) 
     [self logError:request.error]; 

    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(nil, request.error); 
    } 
} 

- (void)backgroundSaveProcessDidSucceed:(VS_CoreDataRequest *)request 
{ 
    // get objects from main thread 
    NSArray *objects = nil; 
    if (request.objects.count > 0) 
    { 
     NSFetchRequest *fetchReq = [NSFetchRequest fetchRequestWithEntityName:[NSString stringWithFormat:@"%@", request.managedObjectClass]]; 
     fetchReq.predicate = [NSPredicate predicateWithFormat:@"self IN %@", request.objects]; 
     objects = [self executeFetchRequest:fetchReq]; 
    } 

    // call the completion block 
    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(objects, nil); 
    } 
} 

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (_managedObjectContext != nil) { 
     return _managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) 
    { 
     // create the MOC for the backgroumd thread 
     _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [_backgroundManagedObjectContext setPersistentStoreCoordinator:coordinator]; 
     [_backgroundManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
     _backgroundManagedObjectContext.undoManager = nil; 

     // create the MOC for the main thread 
     _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     [_managedObjectContext setParentContext:_backgroundManagedObjectContext]; 
     [_managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
    } 

    return _managedObjectContext; 
} 

Есть ли у вас какие-либо идеи, почему происходит этот сбой?

** EDIT **

Дамы и господа, я нашел решение. По-видимому, даже при использовании вложенных контекстов вам все равно придется объединять изменения через NSManagedObjectContextDidSaveNotification. Как только я добавил это в свой код, все стало работать отлично. Ниже мой рабочий код. Спасибо, миллион парней!

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (_managedObjectContext != nil) 
     return _managedObjectContext; 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) 
    { 
     // create the MOC for the backgroumd thread 
     _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [_backgroundManagedObjectContext setPersistentStoreCoordinator:coordinator]; 
     [_backgroundManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
     _backgroundManagedObjectContext.undoManager = nil; 

     // create the MOC for the main thread 
     _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     [_managedObjectContext setParentContext:_backgroundManagedObjectContext]; 
     [_managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:_backgroundManagedObjectContext]; 
    } 

    return _managedObjectContext; 
} 

- (void)saveJsonObjects:(NSDictionary *)jsonDict 
      objectMapping:(VS_ObjectMapping *)objectMapping 
        class:(__unsafe_unretained Class)managedObjectClass 
      completion:(void (^)(NSArray *objects, NSError *error))completion 
{ 
    // perform save on background thread 
    [_backgroundManagedObjectContext performBlock:^(void) 
    { 
     // create a new process object and add it to the dictionary 
     VS_CoreDataRequest *currentRequest = [[VS_CoreDataRequest alloc] init]; 
     currentRequest.managedObjectClass = managedObjectClass; 

     // save the JSON dictionary starting at the upper most level of the key path 
     NSArray *objects = [self saveJSON:jsonDict objectMapping:objectMapping class:managedObjectClass managedObjectContext:_backgroundManagedObjectContext level:0]; 

     if (objects.count == 0) 
     { 
      currentRequest.error = [self createErrorWithErrorCode:100 description:@"No objects were found for the object mapping"]; 
      [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
     } 
     else 
     { 
      // save the objects so we can access them later to be re-fetched and returned on the main thread 
      [currentRequest.objects addObjectsFromArray:objects]; 

      // save the object IDs and the completion block to global variables so we can access them after the save 
      currentRequest.completionBlock = completion; 

      [_backgroundManagedObjectContext lock]; 

      @try 
      { 
       [_backgroundManagedObjectContext processPendingChanges]; 
       [_backgroundManagedObjectContext save:nil]; 
      } 
      @catch (NSException *exception) 
      { 
       currentRequest.error = [self createErrorWithErrorCode:100 description:exception.reason]; 
      } 

      [_backgroundManagedObjectContext unlock]; 

      // complete the process on the main thread 
      if (currentRequest.error) 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidFail:) withObject:currentRequest waitUntilDone:NO]; 
      else 
       [self performSelectorOnMainThread:@selector(backgroundSaveProcessDidSucceed:) withObject:currentRequest waitUntilDone:NO]; 

      // clear out the request 
      currentRequest = nil; 
     } 
    }]; 
} 

- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification 
{ 
    [_managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
} 

- (void)backgroundSaveProcessDidFail:(VS_CoreDataRequest *)request 
{ 
    if (request.error) 
     [self logError:request.error]; 

    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(nil, request.error); 
    } 
} 

- (void)backgroundSaveProcessDidSucceed:(VS_CoreDataRequest *)request 
{ 
    // get objects from main thread 
    NSArray *objects = nil; 
    if (request.objects.count > 0) 
    { 
     NSFetchRequest *fetchReq = [NSFetchRequest fetchRequestWithEntityName:[NSString stringWithFormat:@"%@", request.managedObjectClass]]; 
     fetchReq.predicate = [NSPredicate predicateWithFormat:@"self IN %@", request.objects]; 
     objects = [self executeFetchRequest:fetchReq]; 
    } 

    // call the completion block 
    if (request.completionBlock) 
    { 
     void (^saveCompletionBlock)(NSArray *, NSError *) = request.completionBlock; 
     saveCompletionBlock(objects, nil); 
    } 
} 
+0

Обратите внимание, что вы объединяете изменения в фоновом потоке. Ваши изменения должны быть объединены с помощью 'performBlock/* AndWait * /:', поэтому ваш основной контекст не будет использоваться в фоновом потоке. –

+0

Дэн, ты прав. Спасибо! –

2

Вы можете рассмотреть этот вид контекста архитектуры (непроверенный код):
mainManagedObjectContext инициализируются таким же образом, но с NSMainQueueConcurrencyType и без наблюдателя (кстати, не забудьте удалить ваш наблюдатель)

- (void) mergeChangesFromBackground:(NSNotification*)notification 
{ 
    __block __weak NSManagedObjectContext* context = self.managedObjectContext; 
    [context performBlockAndWait:^{ 
     [context mergeChangesFromContextDidSaveNotification:notification]; 
    }]; 
} 

- (NSManagedObjectContext*) bgContext 
{ 
    if (_bgContext) { 
     return _bgContext; 
    } 

    NSPersistentStoreCoordinator* coordinator = [self persistentStoreCoordinator]; 
    if (!coordinator) { 
     return nil; 
    } 
    _bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    [_bgContext setPersistentStoreCoordinator:coordinator]; 
    [_bgContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
    [_bgContext setUndoManager:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(mergeChangesFromBackground:) 
               name:NSManagedObjectContextDidSaveNotification 
               object:_bgContext]; 
    return _bgContext; 
} 

- (void) doSomethingOnBGContextWithoutBlocking:(void(^)(NSManagedObjectContext*))contextBlock 
{ 
    __block __weak NSManagedObjectContext* context = [self bgContext]; 
    [context performBlock:^{ 
     NSThread *currentThread = [NSThread currentThread]; 
     NSString* prevName = [currentThread name]; 
     [currentThread setName:@"BGContextThread"]; 

     contextBlock(context); 

     [context reset]; 
     [currentThread setName:prevName]; 
    }]; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^