Categories
Swift Development

Core Data and Multiplatform SwiftUI Apps WWDC20

Dub Dub is over and SwiftUI now rules, now it can be used to make full apps through the all ecosystem . But one thing missing on the first beta of Xcode 12 is the Core Data checkbox, it’s a bug? I don’t know, hope we get it back soon but this is how I added Core Data manually

Step 1

Make a new Multiplatform SwiftUI App, so on Xcode new Project> Multiplatform> App and new

This make an Multiplatform app for iOS, iPadOS and macOs
new Multiplatform Apps don’t have AppDelegate and SceneDelegate

Step 2

Time to add or new data model, this was default when we make a core data app on iOS but here we have to added it manually.

so ⌘ + N and we chose Data Model from Core Data section

Don’t forget to check all our targets iOS and macOs also to add the DataModel to the shared Folder

Now we can make or data model like always

Im adding a constraints on name to avoid duplicated values

Step 3

make or SubClass for the data model, this is optional but let me create wrappers for the optionals Strings and Dates so is easy to handle on SwiftUI

First of all now forget to change codegen to manual/none to avoid have an error like this

this happens when we create the subclass but not tell to the data model we are handling it manual

So once we do that we go to editor menu and chose Editor > Create NSManagedObject Subclass

Now we chose or data model

and or entity

same way like we did it before we chose or targets and save the subclass on the shared folder

Voilà we have or subclass now we can handle the wrappers

to avoid optimal string we simply add a new public var

public var wname : String {
      name ?? "No name"
    }

and to make easy the relationship handling we add a new var when we put the relationship like and array

 public var elementArray: [Element] {
        
        let set = elements as? Set<Element> ?? []
         
        return set.sorted {
            $0.wName > $1.wName
        }
        
    }

we do the same on all others entity subclass

Step 4

Connect SwiftUI and CoreData

ok this is the important part, our apps is declared here full on swiftUI

import SwiftUI 

@main
struct ruleOfThreeApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

The new SwiftUI App is elegante and simple, so we are just adding what we need

import CoreData

let context = PersistentCloudKitContainer.persistentContainer.viewContext

ContentView().environment(.managedObjectContext, context)

import SwiftUI
import CoreData

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

Thats all, so now we need a Class to connect to our Data Model

 ⌘ + N and we make a new swiftUI file, we save it on the shared folder and we chose all our targets

So they are two main points in this class

The first is this

 let container = NSPersistentContainer(name: “dataModelName”)

were we put our data Model Name

and the second is this two lines

container.viewContext.automaticallyMergesChangesFromParent = true

container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

where we define or merge Policy

//
//  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)")
            }
        }
    }
}

Step 5

Now we can test or data model

I just added a list and a button to add new elements to my data model

import SwiftUI

struct ContentView: View {
    
    // MARK: - Core Data
    @Environment(\.managedObjectContext) var moc
    
    @FetchRequest(entity: Rule.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Rule.order, ascending: true)] ) var rules: FetchedResults<Rule>
    
    var body: some View {
        List{
            ForEach(self.rules, id: \.self){ rule in
                Text("\(rule.order) \(rule.wname)")
            }
            Button(action: {
                saveTheRule()
            }) {
                Text("Add Rule")
            }
        }
    }

  func saveTheRule(){
        
        //New Rule
        
        let newRule = Rule(context: self.moc)
        
        newRule.baseLabel = "test"
        newRule.name = "Test name \(Int.random(in: 1..<100))" 
        
        
        //simple rule
          
            let newElement = Element(context: self.moc)
         
            newElement.name = "parameter name"
        
            
            newElement.rule = newRule

         try? self.moc.save()
         
    }

}

and now its working

So that’s is hope to get the CoreData checkbook back soon

Thanks for reading this is my first SwiftUI post, hope it helps.

All the info and code are based on this Entry on the Apples Developer Forums

https://developer.apple.com/forums/thread/117655

https://developer.apple.com/forums/thread/117655

https://developer.apple.com/forums/thread/650309

Deja un comentario

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