更改已加载的NSPersistentContainer

时间:2019-01-09 12:29:24

标签: ios swift core-data

我创建了一个单例课程来管理我的核心数据:

class CoreDataManager {
static let sharedManager = CoreDataManager()

private init() {}

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "MyContainer")
    if Globals.profileNumber != 0 {
        let alternateURL = NSPersistentContainer.defaultDirectoryURL()
        let storeURL = alternateURL.appendingPathComponent("\(Globals.profileNumber)MyContainer.sqlite")
        let storeDescription = NSPersistentStoreDescription(url: storeURL)
        container.persistentStoreDescriptions = [storeDescription]
    }
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

// MARK: - Core Data Saving support

func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}
}

但是稍后如何在应用程序中更改persistentContainer指向的存储区?

例如,用户加载应用程序,登录并加载默认的sqlite文件。然后,用户切换到另一个用户帐户,该帐户应“关闭”当前数据库,然后persistentContainer需要加载其他商店?

1 个答案:

答案 0 :(得分:2)

如klaudas提供的链接中所述,将实体与用户建立关系的一个堆栈作为一个很好的选择。

如果您希望拥有单独的商店,则可以尝试以下操作:

class CoreDataManager {
    // The rest of your class...

    private(set) var persistentContainer: NSPersistentContainer?

    func setupNewPersistentContainer(completionHandler: @escaping (_ success: Bool) -> Void) {
        let container = NSPersistentContainer(name: "MyContainer")
        // You should also handle the case where profileNumber == 0 and your store URL can't be constructed.
        if Globals.profileNumber != 0 {
            let alternateURL = NSPersistentContainer.defaultDirectoryURL()
            let storeURL = alternateURL.appendingPathComponent("\(Globals.profileNumber)MyContainer.sqlite")
            let storeDescription = NSPersistentStoreDescription(url: storeURL)
            container.persistentStoreDescriptions = [storeDescription]
        }

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Handle the error.
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }

            let success: Bool = error == nil
            completionHandler(success)
        })

        persistentContainer = container
    }

    // The rest of your class...
}

基本上,您将容器设置逻辑放在一个函数中,该函数在您第一次初始化堆栈并在以后切换帐户时调用。您可以调整类以使persistentContainer成为非可选,或添加一个标志来跟踪商店是否成功加载。

尽管有一些注意事项:

  1. 使用这种方法,您还需要刷新保存在内存中的所有获取的结果控制器和托管对象(因为它们的持久性存储不再可访问)。最简单的方法是在切换时重置整个UI。

  2. 设置新容器时,请等待完成处理程序,然后再继续进行帐户切换流程。

  3. 如果对托管对象有任何引用,则可以通过选中object.managedObjectContext?.persistentStoreCoordinator == context.persistentStoreCoordinator来查看它们在上下文中是否有效。