正确的单例类以使用CoreData

时间:2018-08-01 13:57:37

标签: swift core-data

我正在尝试创建一个与NSManagedObjectContext一起使用的单例类。

这是课程:

import Foundation
import CoreData

class PersistenceService{
    init(){}
    // MARK: - Core Data stack
    static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }

    static var persistentContainer: NSPersistentContainer = {

        let container = NSPersistentContainer(name: "frazeit")
        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
    static func saveContext () {
        let mainContext = persistentContainer.viewContext

        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.parent = mainContext

        privateContext.perform {
            if privateContext.hasChanges {
                do {
                    try privateContext.save()
                } catch {
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }

            }
        }

    }

}

在某些情况下,它不会将更改推送到持久性存储中,而在打开应用程序时,持久性容器已更改,但是当我重新运行时,应用程序更改就消失了。将更改保存到持久性存储中的正确方法是什么。

这是无法正常工作的类:

class func add(word: String, quotes:[Quotes], language: String){
    for item in quotes {
        if let phrase = item.phrase, let author = item.author {
            let quote = CachedQuotes(context: PersistenceService.context)
            quote.phrase = phrase
            quote.date = Date() as NSDate
            quote.keyword = word
            quote.language = language
            quote.author = author
            PersistenceService.saveContext()
        }

    }
}

我称其为保存从网络获取的报价:

override func viewDidLoad() {
    let quotes =  CachedQuotes.getAllQuotes()
    //Prints the number of saved records which is 0 now
    self.getQuote { (result, error) in
        if let qoutes = result?.quotes {
            CachedQuotes.add(word: "friend", quotes: qoutes, language: "en")
        }
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let quotes =  CachedQuotes.getAllQuotes()
    //Prints the number of saved records which is 10 now
}

但是当我重新运行该应用程序时,没有任何内容保存到持久性容器中。

更新: 下面的代码现在可以使用

static func saveContext () {
        let mainContext = persistentContainer.viewContext
        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.automaticallyMergesChangesFromParent = true
        privateContext.parent = mainContext
        privateContext.perform {
            do {
                try privateContext.save()
                mainContext.perform({
                    do {
                        try mainContext.save()
                    } catch {
                        let nserror = error as NSError
                        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                    }
                })
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

首先保存私有队列,然后保存主队列。

2 个答案:

答案 0 :(得分:1)

let mainContext = persistentContainer.viewContext

let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateContext.parent = mainContext

您编辑上下文,然后保存相同的上下文以保留更改。在.viewContext上创建子上下文并保存所述子上下文不会保存.viewContext本身(在此进行更改)。

如果要使用后台队列,请首先在.viewContext上设置var automaticallyMergesChangesFromParent: Bool,在该位置要从后台队列接收更改。然后,您创建一个后台上下文,在其上设置来自.viewContext的相同persistentStoreCoordinator,对其进行更改,然后保存后台队列。

使用privateContext.perform是一个好的开始。如果您首先在创建报价的上下文中包装要引用的更改,那么效果会更好,因此您可以通过上下文使用的同一线程来访问报价。

答案 1 :(得分:1)

这是Apple Refreshing and Maintaining Your App Using Background Tasks示例中的单例。

import Foundation
import CoreData

class PersistentContainer: NSPersistentContainer {
    private static let lastCleanedKey = "lastCleaned"

    static let shared: PersistentContainer = {
        ValueTransformer.setValueTransformer(ColorTransformer(), forName: NSValueTransformerName(rawValue: String(describing: ColorTransformer.self)))

        let container = PersistentContainer(name: "ColorFeed")
        container.loadPersistentStores { (desc, error) in
            if let error = error {
                fatalError("Unresolved error \(error)")
            }

            print("Successfully loaded persistent store at: \(desc.url?.description ?? "nil")")
        }

        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyStoreTrumpMergePolicyType)

        return container
    }()

    var lastCleaned: Date? {
        get {
            return UserDefaults.standard.object(forKey: PersistentContainer.lastCleanedKey) as? Date
        }
        set {
            UserDefaults.standard.set(newValue, forKey: PersistentContainer.lastCleanedKey)
        }
    }

    override func newBackgroundContext() -> NSManagedObjectContext {
        let backgroundContext = super.newBackgroundContext()
        backgroundContext.automaticallyMergesChangesFromParent = true
        backgroundContext.mergePolicy = NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyStoreTrumpMergePolicyType)
        return backgroundContext
    }
}

我个人更喜欢通过依赖注入来传递NSPersistentContainer,但这需要更多的努力。

相关问题