2017-01-17 6 views
1

У меня есть эта модель данных ядра:Правильный способ вставки отношения в Core Data

enter image description here

Иногда, когда я пытаюсь вставить элемент «BoissonCave», мои сбои приложений. Это где это происходит (я чтение данных из массива «значений», который содержит данные в формате JSON):

let boissonCave = BoissonCave(context: context) 
[...] 
if let _regionId = values["regionId"] as? Int16 { 
    let region = CoreDataStack.sharedInstance.getRegion(ofId: Int(_regionId)) 
    boissonCave.fromRegion = region 
} 

Я получаю различные ошибки, либо когда ядро ​​данных выбирает «Регион», или когда я попробуйте назначить fromRegion of boissonCave. Это либо

EXC_BAD_ACCESS

'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'

или даже *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x174259c80> was mutated while being enumerated.'

Я подозреваю, что это проблема контекста, в котором ядро ​​Data пытается принести регион в одном контексте, и вставить BoissonCave в другой? Как мне это решить?

ответ

0

Основано на CoreDataStack. Почему бы вам не использовать 1 статический стек данных ядра? и при необходимости создавать дочерний контекст. Вы всегда можете объединить изменения в дочерний элемент в основной контекст. Это очень немного модифицированная версия от URL выше, что я использовал, так как IOS 10,0

class CoreDataStack { 

    static let shared = CoreDataStack() 

    lazy var persistentContainer: NSPersistentContainer = { 
     let container = NSPersistentContainer(name: "Almanapp") 
     container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
      if let error = error { 
       fatalError("Unresolved error \(error)") 
      } 
     }) 
     return container 
    }() 

    var context : NSManagedObjectContext { 
     return self.persistentContainer.viewContext 
    } 

    func saveContext() { 
     let context = persistentContainer.viewContext 
     if context.hasChanges { 
      do { 
       try context.save() 
      } catch let error as NSError { 
       fatalError("Unresolved error \(error), \(error.userInfo)") 
      } 
     } 
    } 
} 
+0

Спасибо, но синтаксис 'if let' запрещает' _regionId' быть ноль, так что это может быть не проблема. –

+0

Вы цепляете 2 варианта. Одним из них является значение из словаря. Это всегда необязательно, потому что в словаре не может быть такого значения. Другой разбирает его как? Int16, который также является необязательным. Если let заменяет только одно из них. Я адаптирую свой ответ с быстрым тестом на игровые площадки для вас. – Emptyless

+0

Я не совсем понимаю, куда вы идете. Кто-то поправьте меня, если я ошибаюсь, но синтаксис 'if let' предотвращает выполнение закрытого кода, если значение после' = 'действительно является нулем. На примере вашей игровой площадки [поэтому ваш второй 'print' никогда не выполняется] (http://i.imgur.com/JoGejTA.png). То же самое, если вы ищете что-нибудь еще, что '' string "' в вашем 'dict'. Я что-то упускаю ? –

0

Так что же трюк был комбинацией 2 вещей:

во- первых, я уверен, что мой Region и SousRegion объектов были вставлены перед моими BoissonCave объектами, обернув мою вставку коды между context.performAndWait { ... } (вы, конечно, должны использовать один и тот же контекст для обоего вставок)

-I добавил слияние политики в моем контексте, например:

lazy var viewContext: NSManagedObjectContext = { 
    self.persistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump 
    self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true 
    try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current) 

    return self.persistentContainer.viewContext 
}() 

С тех пор я не пострадал.