[英]Migrate local Core Data Store to iCloud for existing project with Swift
I want to enable iCloud for Core Data for an existing project.我想为现有项目启用 iCloud for Core Data。 The user could use the app from a new iPhone or maybe another with his old data.
用户可以使用新 iPhone 或其他 iPhone 上的应用程序使用他的旧数据。 So I have to do a migration of the probably existing store to the new store in iCloud / ubiquitous container.
因此,我必须将可能现有的商店迁移到 iCloud/无处不在的容器中的新商店。
I added the iCloud Document Capabilities and I use the default Core Data Stack Template from Apple, when you create a new Swift-project with iOS 8.当您使用 iOS 8 创建新的 Swift 项目时,我添加了 iCloud 文档功能并使用 Apple 的默认核心数据堆栈模板。
Apple Core Data Stack Template:苹果核心数据栈模板:
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1] as! NSURL
}()
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("testapp", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("testapp.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
let dict = NSMutableDictionary()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict as [NSObject : AnyObject])
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? = {
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save(&error) {
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
}
I read at apple developer about the function migratePersistentStore and here at StackOverflow about the answer Move local Core Data to iCloud , but I don't know how to implement this correct in that template.我在苹果开发人员处阅读了有关 migratePersistentStore 函数的内容,并在 StackOverflow 上阅读了有关将本地核心数据移动到 iCloud的答案,但我不知道如何在该模板中正确实现这一点。
From my understanding, I think, I have to check in the lazy var definition of the coordinator, if the url points to an existing store/file.根据我的理解,我认为,如果 url 指向现有的存储/文件,我必须检查协调器的惰性 var 定义。 If so, I have to migrate to a new store with the function migratePersistentStore:xmlStore and option NSPersistentStoreUbiquitousContentNameKey.
如果是这样,我必须使用函数 migratePersistentStore:xmlStore 和选项 NSPersistentStoreUbiquitousContentNameKey 迁移到新商店。
So I wrote a new persistence coordinator:所以我写了一个新的持久化协调器:
Persistence Coordinator with migration具有迁移功能的持久性协调器
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
// create new iCloud-ready-store
let iCloudStoreUrl = self.applicationDocumentsDirectory.URLByAppendingPathComponent("TestAppiCloud.sqlite")
var iCloudOptions: [NSObject : AnyObject]? = [
NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,
NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true,
NSPersistentStoreUbiquitousContentNameKey: "TestAppiCloudStore"
]
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: iCloudStoreUrl, options: iCloudOptions, error: &error) == nil {
coordinator = nil
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
// Possible old store migration
let existingStoreUrl = self.applicationDocumentsDirectory.URLByAppendingPathComponent("testapp.sqlite")
let existingStorePath = existingStoreUrl.path
// check if old store exists, then ...
if NSFileManager.defaultManager().fileExistsAtPath(existingStorePath!) {
// ... migrate
var existingStoreOptions = [NSReadOnlyPersistentStoreOption: true]
var migrationError: NSError? = nil
var existingStore = coordinator!.persistentStoreForURL(existingStoreUrl)
coordinator!.migratePersistentStore(existingStore!, toURL: iCloudStoreUrl, options: existingStoreOptions, withType: NSSQLiteStoreType, error: &migrationError)
}
// iCloud Notifications
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self,
selector: "storeWillChange",
name: NSPersistentStoreCoordinatorStoresWillChangeNotification,
object: coordinator!)
notificationCenter.addObserver(self,
selector: "storeDidChange",
name: NSPersistentStoreCoordinatorStoresDidChangeNotification,
object: coordinator!)
notificationCenter.addObserver(self,
selector: "storeDidImportUbiquitousContentChanges",
name: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
object: coordinator!)
return coordinator
}()
But I'm getting an exception, when the migration starts at coordinator!.migratePersistentStore:但是当迁移从 coordinator!.migratePersistentStore 开始时,我遇到了一个异常:
var existingStore = coordinator!.persistentStoreForURL(existingStoreUrl) // nil var existingStore = coordinator!.persistentStoreForURL(existingStoreUrl) // nil
but the fileManager says, it exists!但文件管理器说,它存在!
What am I doing wrong?我究竟做错了什么? Is the idea correct?
这个想法正确吗? Please help.
请帮忙。
I ran into the exact same issue with "persistentStoreForURL".我遇到了与“persistentStoreForURL”完全相同的问题。 It turns out what I was looking for would have been something like "persistenStoreWITHUrl".
事实证明,我一直在寻找类似“persistenStoreWITHUrl”的东西。 I assumed incorrectly that it would actually load the store but as it turns out, it does not.
我错误地认为它实际上会加载商店,但事实证明,它不会。 This function works when the store is already loaded in the coordinator.
当商店已经加载到协调器中时,此功能起作用。 I realize you asked this a while ago, but I'm going to leave this here in case anyone else runs into the same issue.
我知道你刚才问过这个问题,但我会把这个留在这里,以防其他人遇到同样的问题。 Changing the code thusly will get it to work as intended:
因此更改代码将使其按预期工作:
let coordinator = self.persistentStoreCoordinator
let existingStore = coordinator.persistentStores.first
var options = Dictionary<NSObject, AnyObject>()
options[NSPersistentStoreRemoveUbiquitousMetadataOption] = true
options[NSMigratePersistentStoresAutomaticallyOption] = true
options[NSInferMappingModelAutomaticallyOption] = true
do {
try coordinator?.migratePersistentStore(existingStore!, to: url2, options: [NSMigratePersistentStoresAutomaticallyOption:true, NSInferMappingModelAutomaticallyOption:true], withType: NSSQLiteStoreType)
}
catch {
print(error)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.