2015-07-28 2 views
2

Я хочу включить iCloud для основных данных для существующего проекта. Пользователь может использовать приложение с нового iPhone или, возможно, другое со своими старыми данными. Так что я должен сделать миграции, вероятно, существующего магазина в новый магазин в iCloud/вездесущем контейнере.Перенос локального хранилища данных ядра в iCloud для существующего проекта с помощью Swift

Я добавил Возможности документа ICloud и я использую по умолчанию основных данных стека шаблона от Apple, когда вы создаете новый Swift-проект с прошивкой 8.

компании Apple Основной шаблон стека данных:

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() 
     } 
    } 
} 

Я прочитал у разработчика Apple о функции migratePersistentStore и здесь, в StackOverflow об ответе Move local Core Data to iCloud, но я не знаю, как реализовать это правильно в этом шаблоне.

С моей точки зрения, я думаю, мне нужно проверить ленивое определение вендора координатора, если URL указывает на существующий магазин/файл. Если это так, мне нужно перейти в новый магазин с помощью функции migratePersistentStore: xmlStore и опции NSPersistentStoreUbiquitousContentNameKey.

Так что я написал новый координатор сохраняемости:

Стойкость координатор миграцией

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 
    }() 

Но я получаю исключение, когда миграция начинается с координатором .migratePersistentStore:

var existingStore = координатор! .persistentStoreForURL (existingStoreUrl) // nil

, но fileManager говорит, что он существует!

Что я делаю неправильно? Правильно ли эта идея? Пожалуйста помоги.

+0

Привет, вы нашли ответ? –

+0

Да, я нашел решение. Но это не хорошо, он может отбрасывать пользовательскую базу данных после обновления приложения. – twofish

ответ

1

Я столкнулся с тем же вопросом с "persistentStoreForURL". Оказывается, то, что я искал, было бы чем-то вроде «persistenStoreWITHUrl». Я предположил неправильно, что он фактически загрузит магазин, но, как выясняется, это не так. Эта функция работает, когда хранилище уже загружено в координатор. Я понимаю, что вы спросили об этом некоторое время назад, но я собираюсь оставить это здесь, если кто-то еще столкнется с тем же вопросом. Таким образом, изменение кода приведет к тому, что он будет работать должным образом:

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) 

    } 
+0

Это прекрасно работает. Ему нужно следующее обновление: попробуйте координатор? .migratePersistentStore (existingStore !, to: url2, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true], withType: NSSQLiteStoreType) – iphaaw

+0

спасибо! Очень признателен! Это было отредактировано! – CodeNoob

Смежные вопросы