在尝试了解有关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分钟才能检索
但是,我希望视图在此期间加载任何我
有。上述方法阻止了我
尽管有明确的调用,但能够保存到上下文
refreshClientInformation中的[self.managedContext save:&error]
每次客户端数据更新后。 refreshPersonalClientInformations
在“客户端获取”线程队列中执行。
- (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中运行save:
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];
});
}];
});
有关如何在后台线程中检索我的信息的任何建议 并且能够将数据保存到磁盘,同时我仍然可以访问我的UI吗?
答案 0 :(得分:1)
您最好创建子上下文以在后台执行所有操作:
dispatch_queue_t fetchQ = dispatch_queue_create("Client Fetch", NULL);
dispatch_async(fetchQ, ^{
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = self.managedObjectContext;
[context performBlock:^{
[self refreshPersonalClientInformation];
dispatch_async(dispatch_get_main_queue(), ^{
[self reload];
});
}];
});