2017-03-23 94 views
1

我有兩個實體(類別,事件),他們有雙向多對多關係。一個類別可以有多個事件,一個事件可以有多個類別。類別到事件的關係是可選的,因爲類別可以在沒有事件的情況下存在,但事件到類別的關係是強制性的(事件不能在沒有類別的情況下存在)。我試圖插入事件並添加類別給他們,但我得到NSValidationErrorValue =關係錯誤。這是我的代碼:核心數據:問題插入數據與關係

private func storeEventsXMLStream(_ xml: XMLIndexer) { 

    let managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.persistentStoreCoordinator 

    // Remove all data before inserting 
    // This line of code is necessary because data needs to be downloaded on daily basis. 
    // Otherwise, I will get redundant data. 
    removeAllExistingData("Event_Ottawa", managedObjectContext: managedObjectContext) 

    autoreleasepool { // Scoping is necessary to fix memory leak 
     for xmlcat in xml["events"]["event"]{ 
      let event = NSEntityDescription.insertNewObject(forEntityName: "Event_Ottawa", into: managedObjectContext) as! Event_Ottawa 
      event.id = Int32((xmlcat.element?.attribute(by: "id")?.text)!)! 
      event.website_url_english = xmlcat["website_url_english"].element?.text 
      event.website_url_french = xmlcat["website_url_french"].element?.text 
      // setting other attributes of events here. Exactly like I did in above 3 line 

      // Just another attribute. Storing it a String in Coredata 
      var recur_rules = "" 
      for rule in xmlcat["recur_rules"]["recur_rule"] { 
       recur_rules += (rule.element?.attribute(by: "weekday")?.text)! 
      } 
      if !recur_rules.isEmpty { 
       event.recur_rules = recur_rules 
      } 


      do { 

       var predicateArray:[NSPredicate] = [] 

       // Categories are inserted to the Coredata before this method call. So I'm fetching the applicable one here. 
       for category in xmlcat["categories"]["category"] { 
        let predicate = NSPredicate(format: "id = %@", (category.element?.attribute(by: "id")?.text)!) 
        predicateArray.append(predicate) 
       } 

       let requestCategory:NSFetchRequest<Category_Event_Ottawa> = Category_Event_Ottawa.fetchRequest() 
       requestCategory.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicateArray) 
       let managedContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType) 
       managedContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.persistentStoreCoordinator 

       let applicableCategories = try managedContext.fetch(requestCategory) 

       for category in applicableCategories { 
        event.addToCategory(category) 
       } 


       } 
      } catch { 
       print(error) 
      } 

     } 

    } 

    // only save once per batch insert 
    do { 
     try managedObjectContext.save() 
    } catch { 
     print(error) 
    } 

    managedObjectContext.reset() <-- I get EXC_BAD_ACCESS, when I use the same object context for fetching as insertion 

} 

我收到的錯誤:

Error Domain=NSCocoaErrorDomain Code=1560 "(null)" UserInfo={NSDetailedErrors=(
"Error Domain=NSCocoaErrorDomain Code=1550 \"The operation couldn\U2019t be completed. (Cocoa error 1550.)\" UserInfo={Dangling reference to an invalid object.=null, NSValidationErrorValue=Relationship 'category' on managed object (0x6100050963f0) 

如果使用插入和取出相同的管理對象方面,我沒有得到這個錯誤了。但是我從重置上下文對象的行中獲取EXC_BAD_ACCESS。我從另一篇文章中瞭解到CoreData不是線程安全的。所以也許這是一個問題。但我該如何解決這個問題?如果相關,則事件類別關係的刪除規則爲Nullify,而類別事件爲級聯。

+0

一些問題/評論:1)當你添加一個新的關係到你的數據模型文件時,'Optional'屬性默認被選中 - 你沒有取消選中這個點?這將是你得到關係錯誤的最簡單的原因。 2)不管錯誤如何,當你在上下文中調用reset()時,你試圖做什麼/期望發生什麼? – MathewS

+0

3)我仍然熟悉使用'NSPersistentContainer'類,但是有沒有什麼原因可以用這種方式創建上下文,而不是使用'PersistentContainer.viewContext'作爲主上下文,'newBackgroundContext()'創建背景上下文喜歡示例代碼顯示? – MathewS

+1

4)線程安全,對於在後臺/專用線程中工作的任何上下文,您應該在上下文的'perform'(async)或'performAndWait'(sync)閉包中執行動作,以防止線程相關的錯誤。https:// developer .apple.com/reference/coredata/nsmanagedobjectcontext/1506578-perform – MathewS

回答

1

在這一行:

requestCategory.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicateArray) 

你創建與AND將一個複合謂語。你要求核心數據獲取你所有的id = 7和id = 8和...等類別。這是行不通的。該類別只能有一個ID。在這種情況下,你實際上需要一個'或'謂詞。

但是,我認爲更好的方法是在您開始循環XML之前將所有類別加載到由其ID標識的字典中,然後將它們從字典中拉出。這比每次讀取都要高效得多。

此外,您不能在單獨的上下文中獲取類別,然後在單獨的上下文中創建對象之間的關係。核心數據將在您嘗試時崩潰。

+0

謝謝指出。因爲這可能是我得到各種奇怪症狀的原因之一(UI在敲擊類別元素時停止響應等)。但我還有一個問題。使用核心數據生成的nsmanaged類來存儲您建議的Dictionary的類別數據是否是好方法?或者我應該爲這件事宣佈新的類別類別? – user30646

+0

您現有的類別實體對我而言是有意義的。我只是建議一個'NSDictionary '來讓你快速查看你現有的類別,而不是每次點擊數據庫。這是否有意義/回答你的問題? –

+0

是的它是有道理的。我會標記你問正確的答案。 – user30646