首页 > 解决方案 > 如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象

问题描述

在下面的代码中,我有一个Listof Cars,并且Car该列表中的每个都有自己的 s 列表,我可以通过调用and毫无问题Service地添加和删除s 。CarcarViewModel.addNewCar(make:String, model:String)carViewModel.deleteCar(at indexSet:IndexSet)

汽车.swift

    import RealmSwift
    final class Car: Object, ObjectKeyIdentifiable{

        @objc dynamic var make: String = ""
        @objc dynamic var model: String = ""
        // creation date, ID etc.
        dynamic var services = List<CarService>()
    }

CarList.swift

    import RealmSwift

    final class CarList: Object, ObjectKeyIdentifiable{
        
        @objc dynamic var name: String = ""
        // creation date, ID etc.
        var cars = RealmSwift.List<Car>()
    }

汽车服务.swift

    import RealmSwift

    final class CarService: Object, ObjectKeyIdentifiable{

        @objc dynamic var serviceName: String = ""
        // creation date, ID etc.
    }

查看模型

    import RealmSwift

    class CarViewModel: ObservableObject{
        @Published var cars = List<Car>()
        @Published var selectedCarList: CarList? = nil

        var token: NotificationToken? = nil
        
        init(){
            // Create a the default lists if they don't already exist.
            createDefaultCarList()
            createDefaultServiceList()
            
            // Initialize the SelectedCarList and the cars variables items from the Default Car List.
            if let list = realm?.objects(CarList.self).first{
                self.selectedCarList = list
                self.cars = list.cars
            }
            
            token = selectedCarList?.observe({ [unowned self] (changes) in
                switch changes{
                case .error(_): break
                case.change(_, _):self.objectWillChange.send()
                case.deleted: self.selectedCarList = nil
                }
            })
        }
        
        func addNewCar(make:String, model:String){
            if let realm = selectedCarList?.realm{
                try? realm.write{
                    let car = Car()
                    car.make = make
                    car.model = model
                    selectedCarList?.cars.append(car)
                }
            }
        }
        
        func deleteCar(at indexSet:IndexSet){
            if let index = indexSet.first,
            let realm = cars[index].realm{
                try? realm.write{
                    realm.delete(cars[index])
                }
            }
        }
        
        func addService(toCar: Car, serviceName: String){
            try? realm?.write{
                let service = CarService()
                service.serviceName = serviceName
                
                toCar.services.append(service)
            }
        }
        
        /// Creates the Default Car List if it doesn't already exists otherwise just prints the error.
        func createDefaultCarList(){
            do {
                if (realm?.objects(CarList.self).first) == nil{
                    try realm?.write({
                        let defaultList = CarList()
                        defaultList.name = "Default Car List"
                        realm?.add(defaultList)
                    })
                }
            }catch let error{
                print(error.localizedDescription)
            }
        }
        
        /// Creates the Default Serivice List if it doesn't already exists otherwise just prints the error.
        func createDefaultServiceList(){
            do {
                if (realm?.objects(ServiceList.self).first) == nil{
                    try realm?.write({
                        let defaultList = ServiceList()
                        defaultList.listName = "Default Service List"
                        realm?.add(defaultList)
                    })
                }
            }catch let error{
                print(error.localizedDescription)
            }
        }
    }

Service我的问题是向现有s添加或删除Cars。当我打电话时,carViewModel.addService(toCar: Car, serviceName: String)我收到以下错误...

调用 addService() 方法。

    struct NewServiceFormView: View {
        @ObservedObject var carViewModel: CarViewModel
        @State var selectedCar:Car // pass from other cars view
        
        var body: some View {
            NavigationView {
            Form {
                // fields
            }
            .navigationBarItems( trailing:Button("Save", action: addNewCar))
            }
        }

        func addNewCar(){
            carViewModel.addService(toCar: selectedCar, serviceName: "Oil Change")
        }
    }

错误

“无法在写入事务之外修改托管 RLMArray。”

我可以通过从列表中Services明确选择一个来添加新的。我没有收到任何错误,但 UI 没有更新;在重新启动应用程序之前,我看不到新添加的服务。Carcars

这样做没有错误,但 UI 不会更新。

carViewModel.addService(toCar: carViewModel.cars[1], serviceName: "Rotors")

如何正确查看、删除和添加Services 到现有Car的 s?

编辑Mahan:根据请求添加了以下代码。

查看以呈现 NewServiceFormView

    struct CarServicesView: View {
        @State var selectedCar:Car // a car from parent view
        @ObservedObject var carViewModel: CarViewModel
        
        var body: some View {
            VStack{

                List {
                    Section(header: Text("Services: \(selectedCar.services.count)")) {
                        ForEach(selectedCar.services) { service in
                        }
                    }
                }
                .listStyle(GroupedListStyle())
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: openNewServiceForm) {
                            Image(systemName: "plus")
                        }
                    }
                }
            }.sheet(isPresented: $newServiceFormIsPresented){
                NewServiceFormView(carViewModel: carViewModel, selectedCar: selectedCar)
            }
        }
        
        func openNewServiceForm() {
        newServiceFormIsPresented.toggle()
        }
    }

标签: swiftuirealmcombinerealm-list

解决方案


一个问题是如何观察 Realm 对象 - 请记住它们是底层的 ObjC 对象,因此您需要使用 Realm 观察者。所以这

@ObservedObject var carViewModel: CarViewModel

应该是这个

@ObservedRealmObject var carViewModel: CarViewModel

请参阅observedRealmObject的文档

另外,请记住,如果您正在观察结果,同样的事情也适用,使用

@ObservedResults

文档所示


推荐阅读