- (IBAction)findContact:(id)sender {
CoreDataAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
// NSManagedObjectContext *context =
// [appDelegate managedObjectContext];
NSManagedObjectContext *managedContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
managedContext = [appDelegate managedObjectContext];
//[context setParentContext:[self managedObjectcontext]];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:@"Contacts"
inManagedObjectContext:managedContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred =
[NSPredicate predicateWithFormat:@"(name == %@)",
_name.text];
[request setPredicate:pred];
[managedContext performBlock:^{
NSError *error = nil;
NSArray *fetchedObjects = [managedContext executeFetchRequest:request error:&error];
_objects = fetchedObjects;
NSManagedObject *matches = nil;
NSLog(@"data= %@", [_objects description]);
if (_objects == nil) {
_status.text = @"No matches";
} else {
matches = _objects[0];
_address.text = [_objects valueForKey:@"address"];
_phone.text = [_objects valueForKey:@"phone"];
_status.text = [NSString stringWithFormat: @"%d matches found", [_objects count]];
}
}];
}
3 回答
注意:以下代码未经测试
要执行后台获取,您首先需要一个后台上下文。
正如@Daniel_G 所说,您正在分配一个新上下文,然后用现有上下文(可能是您的主要上下文)覆盖它。
要创建背景上下文,您将需要NSPersistentStoreCoordinator
:
bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
bgContext.persistentStoreCoordinator = //self.managedObjectContext.persistentStoreCoordinator (the main managed object context coordinator)
//You can set here the undo-manager to nil as well
现在我们有了一个实时的后台上下文,我们可以执行获取并将数据导入到我们的导出上下文/线程:
您的第一个选择是使用持久存储缓存并导入整个对象:(
在这种情况下,您的获取请求的结果类型是NSManagedObjectResultType
)
NSManagedObjectContext* exportContext = self.managedObjectContext; //capture the export context
[bgContext performBlock:^{//Executed on a background thread (most likely not main)
NSError* error = nil;
NSArray* matched = [bgContext executeFetchRequest:request error:&error];
//Check for errors, and count ...
//
//@note: objects contained in matched are not safe to access (even read only ops) in
//any other queue than this
NSManagedObjectID* theId = [matched[0] objectID];
[exportContext performBlockAndWait:^{ //keep the import context alive just in case
//This code is executed on the calling object context queue (probably main)
NSManagedObject* imported = [exportContext objectWithID:theID]; //Will not perform I/O
//Extract the information you need from the imported data.
//if your export context is not main, you will need to update UI elements
//on the main thread (use GCD with main queue ...) and load the data to a
//structure other than a NSManagedObject before moving to the main thread.
//
//@note: If the object matched is deleted after you've taken its ID and before you
// access it on this thread, an exception will be thrown
}];
}];
此处的第二个选项(因为您似乎直接更新了 UI):
构建您的获取请求,如下所示:
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Contacts"];
request.resultType = NSDictionaryResultType;
request.propertiesToFetch = @[@"address",@"phone"];
//Any other settings that you need for your request ...
通过在后台上下文中执行此请求,您将获得包含您请求的信息的字典数组。
这使得获取更有效(更快)。您的提取代码应类似于:
[bgContext performBlock:^{//Executed on a background thread (most likely not main)
NSError* error = nil;
NSArray* matched = [bgContext executeFetchRequest:request error:&error];
//Check for errors, and count ...
//
//@note: matched is an array of dictionaries that can be passed between threads safely
NSDictionary match = matched[0];
dispatch_async(dispatch_get_main_queue(),^{//Executed on main thread
_address.text = [match valueForKey:@"address"];
_phone.text = [match valueForKey:@"phone"];
_status.text = [NSString stringWithFormat: @"%d matches found", [matched count]];
});
}];
通常,不要访问其上下文执行队列之外的托管对象(即使是读取操作也不行)。
Eliminate the perform block call. The fetch is trivial and should take a mere split second, so it is OK to perform it on the UI thread.
Don't let this non-issue seduce you into adopting third party frameworks that promise simplifications but harbour (uncontrollable) complexities of their own.
首先,您能解释一下执行以下操作的目的是什么:
首先,您创建一个具有私有并发类型的新上下文。
NSManagedObjectContext *context = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
现在你把那个上下文重新分配给别的东西?
context = [appDelegate managedObjectContext];
现在您使用的上下文是您在 appDelegate 中定义的上下文...
此外,假设您的 appDelegate 中定义的上下文是正确的,您将在上下文中异步执行获取请求。然后在以下几行中,您检查该提取的结果,而不知道提取请求是否已返回(因为它是异步的)。这解释了为什么您在获取结果后第二次看到结果。一个快速的解决方法是将一些 GCD 加入到上下文块中,如下所示:
[context performBlock:^{
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:request error:&error];
dispatch_async(dispatch_get_main_queue(),^{
_objects = fetchedObjects;
if (_objects == nil) {
_status.text = @"No matches";
} else {
NSLog(@"data= %@", [_objects description]);
NSManagedObject *matches = _objects[0];
_address.text = [matches valueForKey:@"address"];
_phone.text = [matches valueForKey:@"phone"];
_status.text = [NSString stringWithFormat: @"%d matches found", [_objects count]];
}
});
}];
我希望这有帮助?