2017-03-23 3 views
1

Ich habe zwei Entitäten (Kategorien, Ereignis) und sie haben Zwei-Wege-Viele-zu-viele-Beziehung. Eine Kategorie kann mehr als ein Ereignis haben und ein Ereignis kann mehr als eine Kategorie haben. Die Kategorie-zu-Ereignis-Beziehung ist optional in dem Sinne, dass Kategorie ohne ein Ereignis existieren kann, aber die Beziehung von Ereignis zu Kategorie ist obligatorisch (Ereignis kann nicht ohne Kategorie existieren). Ich versuche, Ereignisse einzufügen und Kategorien hinzuzufügen, aber ich bekomme NSValidationErrorValue = Beziehungsfehler. Dies ist mein Code:Core Data: Problem beim Einfügen von Daten mit Beziehung

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 

} 

Und die Fehler, die ich erhalte:

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) 

Wenn den gleichen verwaltete Objektkontext sowohl für das Einsetzen und Abrufen verwenden, ich habe nicht diesen Fehler mehr. Aber ich bekomme EXC_BAD_ACCESS von der Zeile, die Kontextobjekt zurückgesetzt. Ich habe es aus einem anderen Beitrag erfahren, dass CoreData nicht Thread-sicher ist. Vielleicht war das ein Problem. Aber wie behebe ich dieses Problem? Falls es relevant ist, ist die Löschregel für die Event-Kategorie-Beziehung Nulify und Category-Event ist Cascade.

+0

Einige Fragen/Kommentare: 1) Wenn Sie Ihrer Datenmodell-Datei eine neue Beziehung hinzufügen, ist die 'Optional' -Eigenschaft standardmäßig aktiviert - Sie haben dies zu einem bestimmten Zeitpunkt nicht deaktiviert? Das wäre der einfachste Grund, warum Sie den Beziehungsfehler bekommen. 2) Ungeachtet des Fehlers, was versuchst du zu tun/zu erwarten, wenn du 'reset()' im Kontext aufruft? – MathewS

+0

3) Ich bin immer noch vertraut mit der 'NSPersistentContainer' Klasse, aber gibt es irgendeinen Grund, dass Sie Kontext auf diese Weise erstellen anstatt' PersistentContainer.viewContext' für den Hauptkontext und 'newBackgroundContext()' um einen Hintergrundkontext zu erstellen wie Beispielcode zeigt? – MathewS

+1

4) Re-Thread-Sicherheit, für jeden Kontext im Hintergrund/private thread, sollten Sie Aktionen innerhalb der Context 'durchführen' (async) oder' performAndWait' (sync) Schließungen, um Thread-bezogene Fehler zu verhindern https: // Entwickler .apple.com/reference/coredata/nsmanagedobjectcontext/1506578-perform – MathewS

Antwort

1

In dieser Zeile:

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

Sie eine Verbindung Prädikat mit ANDs sind zu schaffen. Sie bitten Core Data, Sie alle Kategorien abzurufen, die ID = 7 UND ID = 8 UND ... usw. haben. Das wird nicht funktionieren. Die Kategorie kann nur eine einzelne ID haben. Sie wollen in diesem Fall ein 'oder' Prädikat.

Ich denke jedoch, der bessere Weg, dies zu tun ist, laden Sie alle Ihre Kategorien in ein Wörterbuch mit ihrer ID vor dem Durchlaufen der XML, und dann ziehen Sie sie einfach aus dem Wörterbuch. Das wird viel leistungsfähiger sein als jedes Mal.

Sie können auch keine Kategorien in einem separaten Kontext abrufen und dann Beziehungen zwischen Objekten aus separaten Kontexten erstellen. Core Data wird abstürzen, wenn Sie es versuchen.

+0

Vielen Dank, dass Sie darauf hingewiesen haben. Weil es vielleicht einer der Gründe ist, warum ich alle Arten von seltsamen Symptomen bekomme (die Benutzeroberfläche reagiert nicht mehr, wenn ich auf das Kategorieelement usw. tippe). Aber ich habe noch eine Frage. Ist es ein guter Ansatz, die von Core Data generierten nsmanaged-Klassen zu verwenden, um die Kategoriendaten für das von Ihnen vorgeschlagene Dictionary zu speichern? Oder sollte ich für diese Angelegenheit eine neue Kategorieklasse deklarieren? – user30646

+0

Ihre bestehende Kategorie Entität macht für mich Sinn. Ich schlage nur ein 'NSDictionary ' vor, um Ihnen eine schnelle Suche nach Ihren vorhandenen Kategorien zu ermöglichen, anstatt jedes Mal auf die Datenbank zu stoßen. Ist das sinnvoll/beantworten Sie Ihre Frage? –

+0

Ja, es macht Sinn. Ich markiere Sie fragen richtige Antwort. – user30646

Verwandte Themen