ios - 核心数据 : Can only use -performBlock: on an NSManagedObjectContext that was created with a queue

标签 ios objective-c core-data swift

我不确定这是怎么回事,但我需要一些帮助。每次用户在 UITextField 中输入文本时,我都试图在后台执行查询。我一直在阅读,看起来我应该如何执行后台 CoreData 操作,但我不断收到此错误:

“只能在使用队列创建的 NSManagedObjectContext 上使用 -performBlock:”

我用谷歌搜索了这个错误,但每个解决方案都说我的上下文需要使用 PrivateQueueConcurrentcyType 创建,我确实这样做了。不知道为什么会这样。也许这是新 iOS 中的错误?

let managedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator
if !textField.text.isEmpty {
    manatedObjectContext.performBlock {
         let objectIDs = //query to get the object IDs

         appDelegate.managedObjectContext.performBlock {
             var objects = Object[]()

             for id in objectsIDs {
                 objects += appDelegate.managedObjectContext.objectWithID(id) as Object
             }

             self.searchResults = objects
             self.searchResultsTableView.reloadData()
         }
    }
}

编辑:我通过执行以下操作解决了我的问题:

  • 将私有(private) managedObjectContext 的父上下文设置为 AppDelegate 的主要上下文
  • 我删除了设置持久存储的行,因为在将父上下文设置为主上下文时不再需要它
  • 我还更改了创建主上下文的默认实现,以使用 MainQueueConcurrencyType 显式创建它

最佳答案

示例取自实际发布的应用,您应该使用 2+ MOC。

  1. 一个用于主线程
  2. 每个后台线程一个。

这允许后台线程安全地执行 MOC 操作,而不会冒相互冲突的风险。注意辅助 MOC 如何使用 -setParentContext: 来引用主 MOC。

这个backgroundMOC,当从后台线程创建和使用时,是安全的,不会抛出错误。

完成修改后,在后台线程上执行保存:

[backgroundMOC performBlockAndWait:^{
    if([backgroundMOC hasChanges]) {
        NSError * error;
        [backgroundMOC save:&error];
        // handle error
    }
}];

要创建上面示例中使用的两个 MOC,您可以使用下面的代码 (ObjC)

对于主线程,使用:

@property(strong) NSManagedObjectContext * 

- (NSManagedObjectContext *)mainMOC mainManagedObjectContext;
{
    NSThread * currentThread = [NSThread currentThread];
    NSAssert([currentThread isMainThread], @"managedObjectContext invoked from %@",currentThread);
    if([currentThread isMainThread]) {
        if(!_mainManagedObjectContext) {
            NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

            if(coordinator) {
                _mainManagedObjectContext = [[NSManagedObjectContext alloc]
                                             initWithConcurrencyType:NSMainQueueConcurrencyType];
                [_mainManagedObjectContext setPersistentStoreCoordinator: coordinator];
                [_mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
            }
        }

        return _mainManagedObjectContext;
    }
    return nil;
}

对于后台线程,使用:

- (NSManagedObjectContext *)threadMOCWithMainMOC:(NSManagedObjectContext *)mainMOC
{
    NSManagedObjectContext * threadManagedObjectContext = [[NSManagedObjectContext alloc]
                                       initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [threadManagedObjectContext setParentContext:[self.db mainManagedObjectContext]];
    [threadManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    return threadManagedObjectContext;
}

关于ios - 核心数据 : Can only use -performBlock: on an NSManagedObjectContext that was created with a queue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24601297/

相关文章:

ios - iOS6 上 MapKit 的性能问题

ios - 下载的 iOS 分发证书不在 'My Certificates' 下

ios - Apple单例代码警告......再次

ios - iOS 的 Firebase 卡在 `Run your app to verify installation`

objective-c - 如何从特定文件夹中读取图像?

iphone - 如何将 UIToolbar 添加到 UIViewController?

objective-c - 如何从静态回调函数中获取对象引用?

swift - Mac OS 更改绑定(bind)核心数据控件的值

ios - 未发布的 xcdatamodel 版本和轻量级迁移

ios - 完全重置 CoreData