При попытке узнать больше о Core Data и многопоточности я написал приложение, которое не удалось сохранить в основных данных. Сначала некоторые фон. Перед тем, как появится мое представление, я создаю управляемый контекст. Это происходит в основной поток:Основные данные Управляемый контекст не сохраняется в многопоточной среде
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.managedObjectContext) [self useDocument];
}
- (void)useDocument
{
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:MY_DOCUMENT];
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];
if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
[document saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
if (success) {
NSLog(@"@@@AMRO--->managedObjectContext has been setup");
self.managedObjectContext = document.managedObjectContext;
[self refresh];
}
}];
} else if (document.documentState == UIDocumentStateClosed) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(@"@@@AMRO--->managedObjectContext has been opened");
self.managedObjectContext = document.managedObjectContext;
[self refresh];
}
}];
} else {
NSLog(@"@@@AMRO--->managedObjectContext has been set");
self.managedObjectContext = document.managedObjectContext;
}
}
Когда появится мой взгляд, я выборки данных от клиента, используя этот подход. причины я делаю это потому, что я не хочу, чтобы мой взгляд, чтобы быть заблокирован как мой клиент обновления происходит:
dispatch_queue_t fetchQ = dispatch_queue_create("Client Fetch", NULL);
dispatch_async(fetchQ, ^{
[self.managedObjectContext performBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self reload];
dispatch_async(fetchQ, ^{
[self refreshClientInformation];
});
});
}];
});
вызова к refreshClientInformation
, занимает около 2 минут, чтобы получить информации, однако, я хочу представление для загрузки в то же время с тем, что у меня есть . Вышеупомянутый подход не позволяет мне быть сохраненным в контексте, несмотря на явный вызов [self.managedContext save:&error]
в refreshClientInformation после каждого обновления данных клиента. refreshPersonalClientInformations
выполняется в очереди потоков «Клиент Fetch».
- (void) refreshPersonalClientInformation
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CLIENT"];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"stationId" ascending:YES]];
NSDate *twoHoursAgo = [NSDate dateWithTimeIntervalSinceNow:-2*60*60];
request.predicate = [NSPredicate predicateWithFormat:@"conditionsUpdated < %@", twoHoursAgo];
NSError *error = nil;
int counter = 0;
// Execute the fetch
NSArray *matches = [self.managedObjectContext executeFetchRequest:request error:&error];
// Check what happened in the fetch
if (!matches) { // nil means fetch failed;
NSLog(@"ERROR: Fetch failed to find CLIENT %@ in database", DEFAULT);
} else if (![matches count]) { // none found, so lets retrieve it below
return;
} else {
for (CLIENT *client in matches) {
NSDictionary *clientDict = [ClientFetcher clientInfo:client.clientId];
client.name = [clientDict[NAME] description];
client.age = [clientDict[AGE] description];
client.updated = [NSDate date];
if (![self.managedObjectContext save:&error]) {
NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@AMRO Unresolved error %@, %@", error, [error userInfo]);
}
//Have to rate limit requests at no more than 10 per minute.
NSLog(@"Sleeping for 6s");
sleep(6);
NSLog(@"Done sleeping for 6s");
}
}
}
Я даже попытался запустить сохранить в refreshPersonalClientInfo делая это:
dispatch_async(dispatch_get_main_queue(), ^{
[self.managedObjectContext save:nil];
});
Но это не сработало, никаких ошибок не было обнаружено
В качестве эксперимента я изменил вызов резьбы на это, когда появляется мое представление, и основные данные ядра в конечном итоге сохраняются, проблема в том, что мое представление заблокировано, и мне нужно долго ждать, пока данные получаются. Кроме того, когда я говорю, в конце концов, я имею в виду, что это не произойдет после того, как я называю [self.managedContext save:nil]
, но через несколько минут:
dispatch_queue_t fetchQ = dispatch_queue_create("Client Fetch", NULL);
dispatch_async(fetchQ, ^{
[self.managedObjectContext performBlock:^{
[self refreshPersonalClientInformation];
dispatch_async(dispatch_get_main_queue(), ^{
[self reload];
});
}];
});
Любые предложения о том, как я должен получить мой informaion в фоновом потоке и быть в состоянии сохранить данные на диск, пока я до сих пор оставляю свой пользовательский интерфейс доступным?
Посмотрите здесь, http://www.cocoanetics.com/2012/07/multi-context-coredata/ – Retro
Поскольку Аарон сказал, что вы должны сделать «детский контекст, чтобы выполнить все в фоновом режиме», как рекомендует Apple, «один ManagedObjectContext не должен использоваться несколькими потоками». – spider1983
Когда вы открываете UIManagedDocument, открытие или сохранение выполняются асинхронно, поэтому вам нужно убедиться, что вы не пытаетесь использовать managedObjectContext до вызова обработчика завершения. Ознакомьтесь с этой ссылкой для получения более подробной информации о ожидании завершения фоновых действий до включения пользовательского интерфейса. В этом примере речь идет об импорте фона из iCloud так же, как и в вашем случае использования. http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/when-to-enable-the-user-interface/ –