ios - NSManagedObjectContext - FetchRequest 死锁

标签 ios swift core-data concurrency deadlock

更新说明:我正在使用 Big Nerd Ranch CoreDataStack如果你们想知道的话。

我已经为这个具体问题苦苦挣扎了一段时间了。基本上我试图从 CNContactStore 获取联系人并在自定义 NSOperation 中获取 ContactDetails (NSManagedObject)。

现在我正在尝试在单元测试上运行整个过程。到目前为止,这就是我的代码的样子。

单元测试

func testThatLoaderOperationWorks()
{   
    var coreDataStack: CoreDataStack?   

    let semaphore = dispatch_semaphore_create(0);

    CoreDataStack.constructSQLiteStack(withModelName: "DataModel") { result in
        switch result
        {
        case .Success(let stack):
            coreDataStack = stack
        case .Failure(let error):
            coreDataStack = nil
            print (error)
        }


        dispatch_semaphore_signal(semaphore);
    }

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)


    let contactStore = CNContactStore()

    let loaderOperation = LoaderOperation.init(withWorkerContext: (coreDataStack?.newChildContext())!, andContactStore: contactStore)
    loaderOperation.completionBlock = {
        XCTAssert(true)
    }

    let operationQueue = NSOperationQueue()
    operationQueue.maxConcurrentOperationCount = 1
    operationQueue.addOperation(loaderOperation)
    loaderOperation.waitUntilFinished()
}

操作子类

override func main()
{       
    let keysToFetch = [
        CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),
        CNContactEmailAddressesKey,
        CNContactPhoneNumbersKey,
        CNContactImageDataAvailableKey,
        CNContactThumbnailImageDataKey]


    var allContainers: [CNContainer] = []
    do
    {
        allContainers = try contactStore.containersMatchingPredicate(nil)
    }
    catch
    {
        print("Error fetching containers")
    }

    var contactList: [CNContact] = []


    for container in allContainers
    {
        let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier)

        do
        {
            let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
            contactList.appendContentsOf(containerResults)
        }
        catch
        {
            print("Error fetching results for container")
        }
    }

    self.workerContext.performBlockAndWait
    {           
        let fetchRequest = NSFetchRequest(entityName: "ContactDetails")
        do
        {
            let list = try self.workerContext.executeFetchRequest(fetchRequest)
            print("The List: \(list)")
        }
        catch
        {
            print(error)
        }
    }
}

从技术上讲,我想要实现的是能够获取联系人并将其与我从 CoreData 获取的数据进行交叉引用。但是当我运行executeFetchRequest 时发生死锁。我是不是在什么地方做错了什么?

最佳答案

我找到了答案。真的很简单。这个主要原因是我试图让测试方法等待 waitUntilFinished() 直到操作结束,并且在操作本身中我试图让它强制等待 performBlockAndWait() 从而导致死锁。

删除 waitUntilFinished() 并将 performBlockAndWait() 替换为 performBlock()

此外,为了使用异步代码进行单元测试,您必须expectationWithDescription("description")

基本上你的单元测试方法应该如下所示

    let asyncExpectation = expectationWithDescription("longRunningFunction")

    .... some stuff here ....


    let loaderOperation = LoaderOperation.init(withWorkerContext: (coreDataStack?.newChildContext())!, andContactStore: contactStore)
    loaderOperation.completionBlock = {
        asyncExpectation.fulfill()
    }

    let operationQueue = NSOperationQueue()
    operationQueue.addOperation(loaderOperation)


    self.waitForExpectationsWithTimeout(10) { (error) in
        XCTAssertNil(error, "Something went wrong")
        XCTAssert(true)
    }

关于ios - NSManagedObjectContext - FetchRequest 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37851888/

相关文章:

ios - 如何在单元格中调用图像 url 和 ImageView 以获取 Collection View 的索引路径功能

ios - 使用 JBChartView 库的分组条形图

android - 本地和远程数据的身份验证的体系结构/实现

ios - 即使在 player.status == .readyToPlay 之后,AVPlayerItem.duration 仍返回 NaN

ios - 是否可以有一个带有两个 UITableView 的 UIViewController,以及两个相应的 NSFetchedResultsController?

swift - 获取 Entities NSSet 的最后一条记录?

ios - 无法在标签中显示经文

ios - Swift 中没有这样的模块,但是 .swift 存在

ios - Swift 中的动态布局?

ios - 错误 : Argument type 'Date?' does not conform to expected type 'ReferenceConvertible'