我有两个实体(类别,事件),他们有双向的多对多关系。一个类别可以有多个事件,一个事件可以有多个类别。类别到事件关系是可选的,因为类别可以在没有事件的情况下存在,但事件到类别关系是必需的(没有类别的事件不能存在)。我试图插入事件并向他们添加类别,但我得到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。
答案 0 :(得分:1)
在这一行:
requestCategory.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicateArray)
您正在使用AND创建复合谓词。您要求Core Data为您提取所有id = 7 AND id = 8 AND ...等的类别。这样做无法正常工作。该类别只能包含一个ID。你真的想要一个&#39;或&#39;在这种情况下的谓词。
但是,我认为更好的方法是在开始循环遍历XML之前将所有类别加载到由其id键入的字典中,然后将它们从字典中拉出来。这比每次抓取都要高得多。
此外,您无法在单独的上下文中获取类别,然后在不同的上下文中创建对象之间的关系。如果您尝试,核心数据将崩溃。