将 Ensembles 添加到现有 Coredata / iCloud 应用程序的步骤

Posted

技术标签:

【中文标题】将 Ensembles 添加到现有 Coredata / iCloud 应用程序的步骤【英文标题】:Steps to add Ensembles to existing Coredata / iCloud App 【发布时间】:2015-10-29 13:35:26 【问题描述】:

短版 (TLDR): 将 Ensembles 集成到已设置为通过 iCloud Drive 将 CoreData 与 iCloud 同步的应用程序中的一般步骤是什么?我很困惑如何使用 Ensembles 来促进同步过程。

加长版: 我是一名新手程序员,我在 iCloud / CoreData 同步方面遇到了困难(见此处ios 9 CoreData / ICloud - No such document at URL)。

我的应用程序运行良好,但云同步除外。一切都已正确配置以与 icloud 驱动器同步 - 它在 99% 的时间内都可以正常工作 - 但我收到的错误会随机破坏我的应用程序,它们来自苹果的代码(“图书管理员返回了一个严重错误......”)。

我的所有数据都在 coredata (sqlite) 中,我的应用程序是用 Swift 2 编写的。

Ensembles 似乎是一个有助于解决我的问题的选项。但是,我完全不知道如何将它集成到我的项目中。拆分整个应用程序的过程让我完全不知所措。谁能提供一些我需要采取的步骤的指导?手册和 github 自述文件非常深入,但我不知道我必须做什么。压倒性的:(

如果有帮助,下面是我的 AppDelegate 文件,我希望所有工作都需要完成...

//MARK: General
func backgroundThread(delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) 
    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)) 
        if(background != nil) background!(); 

        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) 
            if(completion != nil) completion!(); 
        
    



func applicationWillResignActive(application: UIApplication) 
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.

//

func applicationDidEnterBackground(application: UIApplication) 
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    self.saveContext()



func applicationWillEnterForeground(application: UIApplication) 
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    currentiCloudToken = NSFileManager.defaultManager().ubiquityIdentityToken



func applicationDidBecomeActive(application: UIApplication) 
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.



func applicationWillTerminate(application: UIApplication) 
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    // Saves changes in the application's managed object context before the application terminates.
    self.saveContext()


// MARK: - Core Data stack

lazy var managedObjectModel: NSManagedObjectModel = 
    // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
    let modelURL = NSBundle.mainBundle().URLForResource("Model", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
    ()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = 
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)


    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last as NSURL!

    let storeURL = documentsDirectory.URLByAppendingPathComponent("ArrivedAlive.sqlite")

    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    let storeOptions = [NSPersistentStoreUbiquitousContentNameKey: "ArrivedAliveStore", NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]

    do 
        try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: storeOptions)
     catch var error1 as NSError 
        error = error1
        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)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        abort()
     catch 
        fatalError()
    

    return coordinator
    ()


lazy var managedObjectContext: NSManagedObjectContext? = 
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
    let coordinator = self.persistentStoreCoordinator
    if coordinator == nil 
        return nil
    
    var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)

    managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    managedObjectContext.persistentStoreCoordinator = coordinator

    return managedObjectContext
    ()

// MARK: - Core Data Saving support

func saveContext () 
    if let moc = self.managedObjectContext 
        var error: NSError? = nil
        if moc.hasChanges 
            do 
                try moc.save()
             catch let error1 as NSError 
                error = error1
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog("Unresolved error \(error), \(error!.userInfo)")
                abort()
            
        
    

谢谢!

【问题讨论】:

我强烈推荐阅读free book的快速入门章节。 在花了大约 3 小时强调实施 Ensembles 之后,我能够在大约 45 分钟内执行所有更改!你的框架太棒了!!谢谢你! 【参考方案1】:

事实上,将 Ensembles 添加到您的堆栈中并不需要太多的工作。但是,由于您“缺乏经验”,我建议您不要尝试更改现有堆​​栈。

相反,我建议您重写您的堆栈。代码不多。使用 Simple Sync 示例作为您的指南,因为该应用程序使用 iCloud 作为其后端。

一旦您完成了堆栈设置,您的应用程序中就不需要更改太多其他内容,除了确定您想要同步的时间。

【讨论】:

您是否相信诸如“CoreData: Ubiquity: Librarian 在开始下载时返回严重错误Error Domain=BRCloudDocsErrorDomain Code=6”和“CoreData: Ubiquity: Librarian 在开始下载时返回严重错误”等错误错误 Domain=BRCloudDocsErrorDomain Code=5 "No document at URL"" 将按照该示例修复?我的印象是幕后发生了一些我无法从这些错误中修复的事情! 另外,您提到“同步时”。以前,这一切都是由 iCloud 自己处理的,所以这正是我最困惑的领域:( 我只提到这一点是因为您可以将同步设置为在每次保存时自动启动,或定期启动,和/或手动启动。只需将该实现用作参考,您就会明白我在说什么。 谢谢乔迪 - 感谢您的回复。澄清一下——你认为 Ensembles 会帮助解决我在第一条评论中列出的错误吗?还是我一厢情愿? 我已经广泛使用了 Ensembles,它很棒。但是,我没有亲自使用过 iCloud 后端,所以我无法回答这个问题。我知道 iCloud 后端被很多人使用,除了初始设置之外,它的工作原理与我正在做的一样。

以上是关于将 Ensembles 添加到现有 Coredata / iCloud 应用程序的步骤的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 与 Ensembles 的 iCloud 同步

全局标识符? - iCloud + Core Data + Ensembles - 删除对象时重复

核心数据与 Ensembles 同步:在本地模型更改之前,不会拉下远程更改

将 varbinary 更新到现有 SQL 列(添加到现有图像)?

将现有linux用户添加到现有组

Swift Ensembles 设置和 ubiquityContainerIdentifier