【问题标题】:Swift 3 preload from SQL files in appDelegate从 appDelegate 中的 SQL 文件预加载 Swift 3
【发布时间】:2017-02-26 20:41:31
【问题描述】:

我正在尝试快速 3 转换。我在我的 swift 2 项目中从 sql 文件中预加载数据。我不确定如何在 swift 3.0 中完成这项工作?下面是我的 swift 2 appDelegate 文件。在 swift 3 中,核心数据堆栈已经发生了很大的变化,我不知道在哪里尝试重用与 swift 2 相同的代码。我使用的代码列在注释“为 SQLite 预加载添加”下.谢谢

    // MARK: - Core Data stack

lazy var applicationDocumentsDirectory: URL = {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "self.edu.SomeJunk" in the application's documents Application Support directory.
    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return urls[urls.count-1]
}()

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 = Bundle.main.url(forResource: "ESLdata", withExtension: "momd")!
    return NSManagedObjectModel(contentsOf: modelURL)!
}()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    // The persistent store coordinator for the application. This implementation creates and returns 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
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

    let url = self.applicationDocumentsDirectory.appendingPathComponent("ESLdata.sqlite")



    //ADDED FOR SQLITE PRELOAD
    // Load the existing database
    if !FileManager.default.fileExists(atPath: url.path) {
        let sourceSqliteURLs = [Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite")!,Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite-wal")!, Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite-shm")!]
        let destSqliteURLs = [self.applicationDocumentsDirectory.appendingPathComponent("ESLdata.sqlite"), self.applicationDocumentsDirectory.appendingPathComponent("ESLdata.sqlite-wal"), self.applicationDocumentsDirectory.appendingPathComponent("ESLdata.sqlite-shm")]
        for index in 0 ..< sourceSqliteURLs.count {
            do {
                try FileManager.default.copyItem(at: sourceSqliteURLs[index], to: destSqliteURLs[index])
            } catch {
                print(error)
            }
        }
    }
    // END OF ADDED CODE



    var failureReason = "There was an error creating or loading the application's saved data."
    do {
        try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options:  [NSMigratePersistentStoresAutomaticallyOption:true, NSInferMappingModelAutomaticallyOption:true])
    } catch {
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
        dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?

        dict[NSUnderlyingErrorKey] = error as NSError
        let wrappedError = 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 \(wrappedError), \(wrappedError.userInfo)")
        abort()
    }

    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
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext
}()

// MARK: - Core Data Saving support

func saveContext () {
    if managedObjectContext.hasChanges {
        do {
            try managedObjectContext.save()
            print("SAVED")
        } catch {
            print("Save Failed")

            let nserror = error as NSError
            NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
            abort()
        }
    }
}

以下是我尝试更新代码的内容,但没有成功:

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    /*
     The persistent container for the application. This implementation
     creates and returns a container, having loaded 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.
     */





    let container = NSPersistentContainer(name: "ESLdata")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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.

            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
        //ADDED FOR SQLITE PRELOAD

        let url = self.getDocumentsDirectory().appendingPathComponent("ESLdata.sqlite")
        // Load the existing database

        if !FileManager.default.fileExists(atPath: url.path) {
            let sourceSqliteURLs = [Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite")!,Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite-wal")!, Bundle.main.url(forResource: "ESLdata", withExtension: "sqlite-shm")!]
            let destSqliteURLs = [self.getDocumentsDirectory().appendingPathComponent("ESLdata.sqlite"), self.getDocumentsDirectory().appendingPathComponent("ESLdata.sqlite-wal"), self.getDocumentsDirectory().appendingPathComponent("ESLdata.sqlite-shm")]
            for index in 0 ..< sourceSqliteURLs.count {
                do {
                    try FileManager.default.copyItem(at: sourceSqliteURLs[index], to: destSqliteURLs[index])
                } catch {
                    print(error)
                }
            }
        }
        // END OF ADDED CODE


    })
    return container
}()

// MARK: - Core Data Saving support

func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}

【问题讨论】:

  • 具体出了什么问题?说你没有运气并不能描述你遇到的问题。
  • 应用程序将运行。但它并没有像在 swift 2 中那样预加载数据
  • 在我的应用程序中,它运行核心数据,初始数据来自 CSV 文件。因此,每次第一次运行应用程序时都解析一个 CSV 文件,而是解析它一次并直接抓取这些文件并通过应用程序委托加载它们

标签: core-data swift3 ios10


【解决方案1】:

这似乎是我正在寻找的解决方案。据我所知,它是有效的。并为 iOS10 粘贴了新的更纤薄格式的核心数据栈。

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {

    let container = NSPersistentContainer(name: "ESLdata")

    let appName: String = "ESLdata"
    var persistentStoreDescriptions: NSPersistentStoreDescription

    let storeUrl = self.getDocumentsDirectory().appendingPathComponent("ESLData.sqlite")

    if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
        let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
        try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
    }

    let description = NSPersistentStoreDescription()
    description.shouldInferMappingModelAutomatically = true
    description.shouldMigrateStoreAutomatically = true
    description.url = storeUrl

    container.persistentStoreDescriptions = [description]

    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {

            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

【讨论】:

    【解决方案2】:

    首先——您所做的更改只是部分关于 Swift 3。您不需要使用NSPersistentContainer,这样做与使用 Swift 3 完全不同。您仍然可以使用所有相同的与 Swift 2 相同的 Core Data 类和方法,但语法不同。如果您了解旧代码,最好保持相同的逻辑和类,但使用更新的语法。

    如果您确实切换到NSPersistentContainerloadPersistentStores 方法或多或少与旧代码中的addPersistentStore 调用相当。当您调用该方法时,将加载持久存储文件,因此如果您想使用它的数据,它必须存在。在您的旧代码中,您在加载持久存储之前复制预加载的数据,但在您的新代码中,您是在之后进行的。这就是您看不到数据的原因。

    由于您使用的默认存储文件名似乎与NSPersistentContainer 假定的相同,所以这可能就足够了。如果它仍然找不到数据,您可能需要创建一个NSPersistentStoreDescription 来告诉您的容器将存储文件放在哪里。

    但如果我是你,我会坚持使用较旧的方法和较新的 Swift 3 语法。

    【讨论】:

    • 我更喜欢切换到最新最好的更新方式。但是朝着你指出的方向前进,我能够弄清楚:-)
    猜你喜欢
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多