您还可以从a post I made that relates to the same task中获得一些使用:
我正在尝试将旧数据存储迁移到新的对象模型,因此轻量级数据迁移将无法进行。我使用的是映射模型,然后使用一些自定义的NSEntityMigrationPolicy
子类,这些子类主要用于定义辅助方法,然后可以从映射模型中调用该方法。
我一直在边做边学,迁移过程的每个步骤都会失败,然后修复它,然后再进行一些修改,然后陷入困境。
因此,我似乎已经通过了验证步骤,并且模型将保存,但是现在在NSMigrationManager上调用此函数时,我遇到了严重崩溃:
[manager migrateStoreFromURL:sourceStoreURL
type:type
options:nil
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:type
destinationOptions:nil
error:error];
这是那些无用的崩溃之一,因为它是EXC_BAD_ACCESS,我无法确定到底是什么地方或什么原因造成的。我确实知道调试器中的堆栈跟踪如下:
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2c8)
frame #0: 0x000000010ac97ac5 libobjc.A.dylib`objc_msgSend + 5
frame #1: 0x000000010b1911e3 CoreData`_PFManagedObject_coerceValueForKeyWithDescription + 1187
frame #2: 0x000000010b16d9d7 CoreData`_sharedIMPL_setvfk_core + 231
frame #3: 0x000000010b1e4e18 CoreData`-[NSEntityMigrationPolicy createDestinationInstancesForSourceInstance:entityMapping:manager:error:] + 744
frame #4: 0x000000010b22aa67 CoreData`-[NSMigrationManager(InternalMethods) _doFirstPassForMapping:error:] + 407
frame #5: 0x000000010b22c1a3 CoreData`-[NSMigrationManager(InternalMethods) _migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error:] + 2003
frame #6: 0x000000010b228d59 CoreData`-[NSMigrationManager migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error:] + 777
因此,基于第1帧,我猜测它正在尝试将NSNumber迁移到标量。这可能吗?我想知道是否有人将旧商店迁移到允许标量的新商店。
最佳答案
它崩溃的原因是因为在映射模型中定义了某些引用最可能的自定义代码的代码,而该代码失败了。
如果您的实体映射不是很简单,我建议您从该实体映射中删除所有属性映射,然后覆盖:
func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
您在哪里确切指定属性。它也可能与这些自定义方法之一有关,该方法传回
NSManagedObject
的SUBCLASS实例,在迁移期间不应该这样做。您可以在原始问题的堆栈跟踪中看到,尝试将一个值转换为另一个“ coerceValueForKey ...”失败。
例如:
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
let dInstance = NSEntityDescription.insertNewObject(forEntityName: mapping.destinationEntityName!, into: manager.destinationContext)
let text = sInstance.value(forKey: "text") as! String?
dInstance.setValue(sInstance.value(forKey: "lastModified"), forKey: #keyPath(Song.createdAt))
dInstance.setValue(sInstance.value(forKey: "lastModified"), forKey: #keyPath(Song.updatedAt))
dInstance.setValue("txt", forKey: #keyPath(Song.fileExtension))
dInstance.setValue(sInstance.value(forKey: "filename"), forKey: #keyPath(Song.filename))
dInstance.setValue(sInstance.value(forKey: "firstLetterUppercase"), forKey: #keyPath(Song.firstLetterUppercase))
dInstance.setValue(sInstance.value(forKey: "name"), forKey: #keyPath(Song.title))
dInstance.setValue(sInstance.value(forKey: "oldFilename"), forKey: #keyPath(Song.oldFilename))
dInstance.setValue(self.songDataLengthOfText(text), forKey: #keyPath(Song.songDataLength))
dInstance.setValue(text, forKey: #keyPath(Song.text))
dInstance.setValue(SongDataType.plainText.rawValue, forKey: #keyPath(Song.typeRaw))
dInstance.setValue(nil, forKey: #keyPath(Song.userInfoData))
// my new data model added a to-one association to a Song that wasn't present previously. So we have to create it,
// but not yet associate it. We just provide a means to associate it, via the filename/songFilename
let songData = NSEntityDescription.insertNewObject(forEntityName: SongData.entity().name!, into: manager.destinationContext)
songData.setValue(sInstance.value(forKey: "filename"), forKey: #keyPath(SongData.songFilename))
let structure = SongDataStructure() // don't worry about this. It's used for serialization.
structure.set(text: text)
songData.setValue(structure.serialize(), forKey: #keyPath(SongData.nsdata))
// my new data model added a to-one association to a Song that wasn't present previously. So we have to create it,
// but not yet associate it. We just provide a means to associate it, via the filename/songFilename
let viewPreferences = NSEntityDescription.insertNewObject(forEntityName: SongViewPreferences.entity().name!, into: manager.destinationContext)
viewPreferences.setValue(sInstance.value(forKey: "filename"), forKey: #keyPath(SongViewPreferences.songFilename))
// important to associate these!
manager.associate(sourceInstance: sInstance, withDestinationInstance: dInstance, for: mapping)
return
}