Categories
Swift Development

Core Data & CloudKit in the New MultiPlatform Apps of SwiftUI

On my last post I added Core Data to my SwiftUI Multiplatform project, I a get some feedback on twitter and now I can show your how to add CloudKit to Synchronize data between your devices

if haven’t read that Entry this is the link

So first of all I wanna say thanks to Malcom Hall

He give me a better approach to the Core Data class so now we are using the new @StateObject

Step 1

so first of all we are gonna make a little refactor to our code on the PersistentCloudKitContainer.swift Class

Right now the class looks like this

//
//  PersistentCloudKitContainer.swift
//  ruleOfThree
//
//  Created by Francisco Misael Landero Ychante on 27/06/20.
//

import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "ruleOfThree")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return container
    }()
    // MARK: - Core Data Saving support
    public static 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)")
            }
        }
    }
}

So first of all we are gonna make the class conforms to ObservableObject

...
public class PersistentCloudKitContainer: ObservableObject {
...

Next we are gonna delete the follow lines

...  
// MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
...

next we are changing or var persistentContainer to be lazy and also to return a NSPersistentCloudKitContainer

... 
// MARK: - Core Data stack
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "yourModelDataName")
...

also we are adding the next unwrapper

...
guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
 description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
...

So this is what we have now

import CoreData
public class PersistentCloudKitContainer: ObservableObject {
    
    // MARK: - Core Data stack
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "ruleOfThree")
        
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No descriptions found")
        }
        
        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        NotificationCenter.default.addObserver(self , selector: #selector(processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)
        
        return container
    }()
    
}

Next we are gonna make a little changes on or @main

import SwiftUI
import CoreData

@main
struct ruleOfThreeApp: App {
    @StateObject var coreData = PersistentCloudKitContainer()
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, coreData.persistentContainer.viewContext)
        }
    }
}

Cool now we can add CloudKit

Step 2

adding Cloud Kit

So now we go to our Project file and were we have our targets we chose iOS, then singning & Capabilities

Now on the button + capability we chose iCloud

Once added we select the CloudKit checkbox and then on containers we select our container if you don’t have one make a new one just write the name and its ready.

We make the same for macOs

Step 3

Now we go to our Data Modelo and under Configurations > Default we open the inspector on the lateral side an chose Use with CloudKit

And that’s all, we now can run or simulator and test, you need to login on the simulator with the same iCloud account

References

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *