Безопасность CoreData и потоков

У меня есть одноэлементное имя CoreDataManager котором зарегистрирован mergeContextChangesForNotification :

 + (id) sharedManager{ static CoreDataManager *mSharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ mSharedManager = [[CoreDataManager alloc] init]; }); return mSharedManager; } - (id)init { self = [super init]; if (self) { dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:nil]; }); } return self; } 

после получения уведомления:

 - (void)mergeContextChangesForNotification:(NSNotification *)notification { [shareContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:YES]; } 

У меня есть два вопроса:

  1. Должен ли я использовать performSelectorOnMainThread здесь? так как в этом ответе говорится, что никогда. Я должен изменить его на GCD и использовать dispatch_get_main_queue ??
  2. mergeContextChangesForNotification ли регистрация mergeContextChangesForNotification в init является хорошей практикой для обеспечения того, чтобы уведомление всегда регистрировалось в основном потоке? который я прочитал из этого ответа

2 Solutions collect form web for “Безопасность CoreData и потоков”

При использовании типов параллелизма управляемых объектов, представленных в iOS 5 / OS X 10.7, предпочтительно использовать методы performBlock для обеспечения выполнения операции Core Data в правом потоке (точнее: в правой очереди).

Таким образом, вы создадите общий контекст с помощью

 shareContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

и слияние изменений из других контекстов с

 - (void)mergeContextChangesForNotification:(NSNotification *)notification { [shareContext performBlock:^{ [shareContext mergeChangesFromContextDidSaveNotification:notification]; }]; } 

Также обратите внимание, что (как указано в документации NSManagedObjectContext ), рекомендуется регистрироваться для сохранения уведомлений только из известных контекстов. С object:nil в вашей регистрации вы можете получить неожиданные уведомления, потому что системные фреймворки используют Core Data внутренне.

Поэтому вы должны либо зарегистрироваться только для создаваемых вами контекстов. Кроме того, вы можете проверить, что уведомление было отправлено из контекста с тем же постоянным координатором хранилища:

 - (void)mergeContextChangesForNotification:(NSNotification *)notification { NSManagedObjectContext *otherContext = [notification object]; if (otherContext != shareContext && [otherContext persistentStoreCoordinator] == [shareContext persistentStoreCoordinator]) { [shareContext performBlock:^{ [shareContext mergeChangesFromContextDidSaveNotification:notification]; }]; } } 

Наконец, метод уведомления всегда вызывается в потоке, на котором он был отправлен . Неважно, в каком потоке зарегистрировано уведомление. Поэтому отправка регистрации в основной поток не требуется.

Проверьте пример приложения TopSongs , имейте в виду, что они не идеальны, но большую часть времени можно использовать для справки. Они синхронизируют вызовы mergeChangesFromContextDidSaveNotification должны выполняться только в основном потоке, но делая это немного более элегантным способом:

 // This method will be called on a secondary thread. Forward to the main thread for safe handling of UIKit objects. - (void)importerDidSave:(NSNotification *)saveNotification { if ([NSThread isMainThread]) { [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; [self.songsViewController fetch]; } else { [self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO]; } } 

Что касается инициализации, то -init будет вызываться в том же потоке, на +sharedManager был вызван +sharedManager .

Кроме того, поскольку второй ответ, который вы связали, не очень информативен с точки зрения документации, позвольте мне оставить ссылку на раздел « Параллелизм с основными данными » в документах.

Interesting Posts

Swift: класс уровня нагрузки целым числом

ios9 mobile safari пейзаж css ошибка с положением: абсолютное дно: 0

сохранить CLLocation на plist

Раскадровка iOS XCode LawnScreen не отображается

UITableViewAutomatic Ограничения на разрыв?

Запуск телефона / электронной почты / ссылок на карту в WKWebView

добавить путь поиска заголовка пользователя к podspec

добавить проблему с просмотром SplitViewController в iOS5

UITableView не перезагружает данные или вызывает cellForRowAtIndexPath

Класс Firebase FIRAAppEnvironmentUtil реализуется как при использовании Cocoapods

Как отключить пункты всплывающего меню, такие как «Выбрать», «Выбрать все», «Предложить …», «Определить» (в UIWebView)?

Как изменить рамку считывателя ZBar?

Кэширование изображения и UICollectionView

как обернуть асинхронный метод, который принимает блок и превратить его синхронно в объективе c

MobileSafari (iOS Safari): Есть ли способ предотвратить «привязку» горизонтальной / вертикальной прокрутки?

PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.