在 MVVM 应用程序中访问核心数据堆栈

paw*_*222 3 singleton core-data ios swift

我正在使用该MVVM模式编写应用程序。我想知道如何创建CoreData堆栈,以便可以从我的应用程序的各个位置访问它。

第一种方法是在 中创建一个持久性容器AppDelegate,然后将此服务注入我的 ViewModel(同时将其managedObjectContext作为环境变量传递给我的视图)。

然而,通过这种方式,访问整个应用程序的上下文更加困难:例如,在解码网络响应时,因为他们无法访问managedObjectContext

protocol APIResource {
    associatedtype Response: Decodable
    ...
}

extension APIResource {
    func decode(_ data: Data) -> AnyPublisher<Response, APIError> {
        Just(data)
            // how can I access context here to pass it to JSONDecoder?
            .decode(type: Response.self, decoder: JSONDecoder())
            .mapError { error in
                .parsing(description: error.localizedDescription)
            }
            .eraseToAnyPublisher()
    }
}
Run Code Online (Sandbox Code Playgroud)

我见过的另一个解决方案是使用单例。我可以从项目的任何地方访问它,但如何以正确的方式创建它?

如果我不想同时修改队列和后台队列中的某个对象怎么办?或者如果两个队列都想修改同一个对象怎么办?

use*_*632 5

您可以使用 Core Data Singleton 类

import CoreData

class CoreDataStack {
    static let shared = CoreDataStack()

    private init() {}

    var managedObjectContext: NSManagedObjectContext {
        return self.persistentContainer.viewContext
    }

    var workingContext: NSManagedObjectContext {
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        context.parent = self.managedObjectContext
        return context
    }

    // MARK: - Core Data stack

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "MyStuff")
        container.loadPersistentStores(completionHandler: { storeDescription, error in
            if let error = error as NSError? {
                RaiseError.raise()
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext() {
        self.managedObjectContext.performAndWait {
            if self.managedObjectContext.hasChanges {
                do {
                    try self.managedObjectContext.save()
                    appPrint("Main context saved")
                } catch {
                    appPrint(error)
                    RaiseError.raise()
                }
            }
        }
    }

    func saveWorkingContext(context: NSManagedObjectContext) {
        do {
            try context.save()
            appPrint("Working context saved")
            saveContext()
        } catch (let error) {
            appPrint(error)
            RaiseError.raise()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

核心数据不是线程安全的。如果您在 manageObject 上写了一些东西并且不想保存它,但是其他一些线程保存了上下文,那么您不想保留的更改也将保留。

因此,为避免这种情况,请始终创建工作上下文 - 这是私有的。

当您按保存时,将保存第一个私有上下文,然后保存主上下文。

在 MVVM 中,您应该拥有 DataLayer,您的 ViewModel 通过它与 Core Data 单例类进行交互。