核心数据:在插入关系

时间:2017-03-23 13:40:35

标签: ios core-data swift3

我有两个实体(类别,事件),他们有双向的多对多关系。一个类别可以有多个事件,一个事件可以有多个类别。类别到事件关系是可选的,因为类别可以在没有事件的情况下存在,但事件到类别关系是必需的(没有类别的事件不能存在)。我试图插入事件并向他们添加类别,但我得到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,而类别事件是Cascade。

1 个答案:

答案 0 :(得分:1)

在这一行:

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

您正在使用AND创建复合谓词。您要求Core Data为您提取所有id = 7 AND id = 8 AND ...等的类别。这样做无法正常工作。该类别只能包含一个ID。你真的想要一个&#39;或&#39;在这种情况下的谓词。

但是,我认为更好的方法是在开始循环遍历XML之前将所有类别加载到由其id键入的字典中,然后将它们从字典中拉出来。这比每次抓取都要高得多。

此外,您无法在单独的上下文中获取类别,然后在不同的上下文中创建对象之间的关系。如果您尝试,核心数据将崩溃。