Swift - SwiftUI Article

CoreData - der einfache Weg

event 22. April 2021

In diesem Artikel, werde ich euch einen einfachen Einstieg in CoreData mit SwiftUI erklären. CoreData ist nicht mehr so schwierig als es vor Jahren war.

CoreData Create

Als erstes erstellt ein neues Xcode Projekt mit dem Namen „UserList“, mach einen Haken bei CoreData und wir nutzen SwiftUI. Speichert das Projekt am Ort eurer Wahl.

In diesem Fall nutzen wir teilweise die bereitgestellten Swift Dateien und teilweise den bereitgestellten Code. Als erstes schauen wir uns das UserList.xcdatamodeld an und verändern die Einträge.

CoreData Model

Wir erstellen/ändern die Entity zu User mit einem Attribute name welche wird den Typen String zu ordnen. Außerdem wählen wir das Attribute wie oben aus und nehmen den Haken bei Optional raus. Da der Name bei User immer vorhanden ist und nicht Optional ist.

Als nächstes löschen wir die Persistence.swift Datei, da wir unsere eigene Swift Datei erstellen. Wir erstellen nun eine neue Swift Datei und benennen sie -> CoreDataStack.swift.

Füge den unterstehenden Code zur CoreDataStack.swift Datei hinzu.


    import CoreData

    public class PersistentContainer: NSPersistentContainer {}
    
    public class CoreDataStack {
    
        public let persistentContainer: NSPersistentContainer
    
        public init() {
        persistentContainer = PersistentContainer(name: "UserList")
    
        persistentContainer.loadPersistentStores(completionHandler: { description, error in
            if let error = error {
            fatalError("Core Data store failed to load with error: \(error)")
            }
        })
        }
    }
    
    public extension CoreDataStack {
        func saveUser(named name: String) {
        let user = User(context: persistentContainer.viewContext)
        user.name = name
    
        do {
            try persistentContainer.viewContext.save()
            print("User saved succesfully")
        } catch {
            persistentContainer.viewContext.rollback()
            print("Failed to save movie: \(error)")
        }
        }
    }
    
    public extension CoreDataStack {
        func getAllUsers() -> [User] {
        let fetchRequest: NSFetchRequest = User.fetchRequest()
    
        do {
            return try persistentContainer.viewContext.fetch(fetchRequest)
        } catch {
            print("Failed to fetch movies: \(error)")
            return []
        }
        }
    }
    
    public extension CoreDataStack {
        func deleteUser(_ user: User) {
        persistentContainer.viewContext.delete(user)
    
        do {
            try persistentContainer.viewContext.save()
        } catch {
            persistentContainer.viewContext.rollback()
            print("Failed to save context: \(error)")
        }
        }
    
        func updateUser(_ user: User) {
        do {
            try persistentContainer.viewContext.save()
        } catch {
            persistentContainer.viewContext.rollback()
            print("Failed to save context: \(error)")
        }
        }
    }

Als erstes erstellen wir einen Klasse und initialisieren das Datenmodel. Dann haben wir drei Extensions in dem wir den User speichern, aufrufen oder löschen. Der User wird dann mit dem Datenmodel synchronisiert.

Eine weitere Änderung müssen wir noch in der Datei UserListApp.swift vornehmen um unser CoreDataStack in SwiftUI bereit zu stellen.


    import SwiftUI

    @main
    struct UserListApp: App {
    
        var body: some Scene {
            WindowGroup {
                ContentView(coreDataStack: CoreDataStack())
            }
        }
    }

Hier rufen wir das CoreDateStack auf und Verknüpfen das Stack mit dem ContentView. Im ContentView.swift habe ich den Code wie folgend:


    import SwiftUI
    import CoreData
    
    struct ContentView: View {
        let coreDataStack: CoreDataStack
        
        @State var userName = ""
        @State var users : [User] = []
        
        var body: some View {
            VStack {
                Text("Add a user")
                    .font(.title)
                    .padding()
                
                HStack {
                    TextField("Type user name", text: $userName)
                    
                    Button("Save user") {
                        coreDataStack.saveUser(named: userName)
                        users = coreDataStack.getAllUsers()
                    }
                    
                    Spacer()
                    
                }.padding()
                
                List {
                    ForEach(users) { (user: User) in
                        Text(user.name ?? "")
                    }.onDelete { rows in
                        for row in rows {
                            let user = users[row]
                            coreDataStack.deleteUser(user)
                        }
                        
                        users.remove(atOffsets: rows)
                    }
                }.onAppear {
                    users = coreDataStack.getAllUsers()
                }
            }.padding()
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView(coreDataStack: CoreDataStack())
        }
    }

Im ContenView erstellen wir das Design der App, hier sind euch keine Grenzen gesetzt. Wir erstellen ausserdem eine Konstante für das CoreDataStack und rufen dessen Funktionen auf.

Ich wollte mit diesem Artikel nur kurz zeigen, wie einfach es ist CoreData in einer App ein zu binden. Den Code für dieses Projekt findet auch auf Github:

https://github.com/DKoenig82/medium/tree/main/UserList

swift swiftui
David Koenig Swift Developer

David Koenig

Swift Developer & Autor