-1
- (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]];
            }

    }];
}
4

3 回答 3

0

注意:以下代码未经测试

要执行后台获取,您首先需要一个后台上下文。
正如@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]];
    });
}];

通常,不要访问其上下文执行队列之外的托管对象(即使是读取操作也不行)。

于 2013-09-14T19:59:33.173 回答
0

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.

于 2013-09-11T16:42:08.283 回答
0

首先,您能解释一下执行以下操作的目的是什么:

首先,您创建一个具有私有并发类型的新上下文。

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]];
       }
    });
}];

我希望这有帮助?

于 2013-09-11T19:30:42.990 回答