2016-06-16 9 views
0

更新のお知らせ:私はBig Nerd Ranch CoreDataStackを使用しています。NSManagedObjectContext - FetchRequestデッドロック

私は今この特定の問題にしばらく苦しんでいます。基本的に私は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) 
     } 
    } 
} 

技術的には私が達成しようとしていることの連絡先を取得することが可能で、クロスIデータとそれらを参照しますCoreDataからフェッチします。しかし、私はexecuteFetchRequestを実行するとデッドロックが発生します。私はどこかで何か間違っているのですか?

答えて

0

私は答えを見つけました。本当にシンプル。この主な原因は、操作が終了するまで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) 
    } 
のように見えるはずです
関連する問題