2016-01-07 13 views
3

我得到在我的單元測試拋出的異常,對核心數據的線程此消息:調試核心數據__NSCFSet ADDOBJECT無例外

CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil' 
*** First throw call stack: 
(
    0 CoreFoundation      0x00683a14 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x02334e02 objc_exception_throw + 50 
    2 CoreFoundation      0x0068393d +[NSException raise:format:] + 141 
    3 CoreFoundation      0x005595b9 -[__NSCFSet addObject:] + 185 
    4 CoreData       0x001d47c0 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processPendingInsertions:withDeletions:withUpdates:] + 560 
    5 CoreData       0x001cee8a -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2410 
    6 CoreData       0x001ce506 -[NSManagedObjectContext processPendingChanges] + 54 
    7 CoreData       0x001f359b developerSubmittedBlockToNSManagedObjectContextPerform + 443 

我試圖確定是什麼原因引起的,但由於它發生在NSManagedObjectContext隊列中,所以線程沒有任何自己的代碼的堆棧跟蹤。

我在-[__NSCFSet addObject:]-[NSManagedObjectContext processPendingChanges]上設置了符號斷點,但無法在停止時看到任何狀態,幫助我確定哪些對象導致問題。

下一步發生在我身上的是嘗試使用swizzling -[__NSCFSet addObject:]來添加我自己的實現,所以我只能在參數爲零時才能停止。希望該集合不是空的,並且在插入nil之前通過查看它的內容我可以獲得更多的信息。但是,我遇到了困難,因爲它是一個私人課程。

使用上面的方法,或者我沒有考慮過的方法,如何獲得有關導致異常的更多信息?

+2

看起來像併發問題。爲您的項目方案添加一個「-com.apple.CoreData.ConcurrencyDebug 1」參數。 – bteapot

+0

@bteapot這正是我所需要的。如果你能給出更多擴展的答案,我會接受它。 – Dov

回答

5

感謝@bteapot的暗示我將-com.apple.CoreData.ConcurrencyDebug 1參數添加到我的方案中。我從Ole Begemann的優秀Core Data Concurrency Debugging文章中獲得了有關這種工作原理的更多信息。

添加此標誌會導致一旦您的代碼從不正確的線程調用NSManagedObjectContext時拋出異常。這在Xcode的偉大工程,但被告知,在Xcode的機器人,這會導致測試失敗,這無益消息:

Lost connection to test manager service

+0

非常感謝! – Kukiwon

+0

我通常不會寫感謝之類的,但是對於這個計劃的論點來說,投票是不夠的......你和@bteapot是明星... –

+0

@Dov:什麼是真正的問題?使用錯誤的上下文與線程組合? – shallowThought

0

我有這個同樣的問題,今天它掙扎了一整天。添加併發調試對我來說是一個正確的方向,但潛在的問題是我試圖從不同的線程訪問同一個託管對象上下文的實例。導致我崩潰的方法是試圖返回一個提取的對象。我能夠通過將我的do,try,catch塊包裝在context.perform塊中並使該方法將一個轉義閉包作爲參數而不是返回該對象來修復它。

func fetchUser(id: Int, completion: @escaping (User) ->()) { 
    let predicate = NSPredicate(format: "id = %d", id) 
    let request: NSFetchRequest<User> = User.fetchRequest() 
    request.predicate = predicate 
    context.perform { 
     // try to fetch user from core data 
     do { 
      if let user = try self.context.fetch(request).first { 
       completion(user) 
      } else { 
       // if no user exists with that id, create and return a new user 
       self.seedAutoPopulatingLists(for: id) 
       completion(NSEntityDescription.insertNewObject(forEntityName: "User", into: self.context) as! User) 
      } 
     } catch let error as NSError { 
      print("Could not fetch: \(error) \(error.userInfo)") 
     } 
    } 
} 

希望這可以幫助任何人在未來遇到這種情況。