簡體   English   中英

將核心數據從 Swift 遷移到 SwiftUI

[英]Migrate Core Data from Swift to SwiftUI

我正在嘗試將應用程序從 Swift 遷移到 SwiftUI 但正在努力處理核心數據。 我在相同的包標識符下同時運行 Swift 和 SwiftUI 應用程序,因此它們正在訪問相同的基礎數據,但是盡管我使用相同的 xcdatamodeld model 名稱來指向兩個數據庫,但它們都指向不同的數據庫。

我需要做的是在 Swift 上運行應用程序並將數據加載到核心數據中。 然后重新運行 SwiftUI 版本的應用程序並能夠加載相同的數據。

這里是 Swift 版本的代碼:

class DataStore {
    static let sharedDataStore = DataStore()
    var managedContext: NSManagedObjectContext!
    
    lazy var coreDataStack = CoreDataStack()
    
    fileprivate init() {
        self.managedContext = coreDataStack.context
    }
    
    func createParcours() -> Parcours {
        let parcours = Parcours(context: managedContext)
        parcours.timeStamp = NSDate()
        return parcours
    }
    
    func deleteParcours(_ toDelete: Parcours) {
        managedContext.delete(toDelete)
        self.saveParcours()
    }
    
    func saveContext(parcours: Parcours?) {
        if let parcours = parcours {
            encodeParcours(parcours)
        }
        coreDataStack.saveContext()
    }
}



class CoreDataStack {
    
    let modelName = "MyParcours" // Exactly same name as name.xcdatamodeld
    
    fileprivate lazy var applicationDocumentsDirectory: URL = {
        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1]
    }()
    
    lazy var context: NSManagedObjectContext = {
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = self.psc
        return managedObjectContext
    }()
    
    fileprivate lazy var psc: NSPersistentStoreCoordinator = {
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        
        let url = self.applicationDocumentsDirectory.appendingPathComponent(self.modelName)
        
        do {
            let options = [NSMigratePersistentStoresAutomaticallyOption: true]
            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
        } catch {
            // Report any error we got.
            var dict = [String: AnyObject]()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
            dict[NSLocalizedFailureReasonErrorKey] = "There was an error creating or loading the application's saved data." 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
    }()
    
    fileprivate lazy var managedObjectModel: NSManagedObjectModel = {
        let modelURL = Bundle.main.url(forResource: self.modelName, withExtension: "momd")!
        return NSManagedObjectModel(contentsOf: modelURL)!
    }()
    
    func saveContext () {
        
        guard context.hasChanges else {return}
        
        do {
            try context.save()
        } catch let error as NSError {
            print("Unresolved error: \(error), \(error.userInfo)")
        }
    }
}

在 SwiftUI 版本中,我生成 NSPersistentContainer() 並將其注入 ContentView:

class DataController: ObservableObject {
    let container = NSPersistentContainer(name: "MyParcours")
    
    init() {
        container.loadPersistentStores { NSEntityDescription, error in
            if let error = error {
                print("Core Data failed to load: \(error.localizedDescription)")
            }
        }
    }
}

@main
struct MySwiftUIApp: App {
    @StateObject private var dataController = DataController()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, dataController.container.viewContext)
        }
    }
}

任何指示我哪里出錯了?

我發現為什么數據庫沒有出現在應用程序的 SwiftUI 版本中。 原因是Apple在iOS的某些早期版本中更改了存儲位置(不確定具體時間),最初位於Documents文件夾中,現在位於Library/Application%20Support中。 所以解決的辦法是改變NSPersistentStoreDescription的url:

init() {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let documentsDirectory = paths[0].appendingPathComponent("MyParcours")
        
        self.container = NSPersistentContainer(name: "MyParcours")
        
        // Change URL to allow for compatibility with older version in Swift
        let description = NSPersistentStoreDescription(url: documentsDirectory)
        container.persistentStoreDescriptions = [description]
        
        container.loadPersistentStores { NSEntityDescription, error in

        etc.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM