如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象
Posted
技术标签:
【中文标题】如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象【英文标题】:How to add and delete objects from a List from an object who's inside another List in SwiftUI and Realm 【发布时间】:2021-08-16 13:44:33 【问题描述】:在以下代码中,我有一个Car
s 的List
,并且该列表中的每个Car
都有自己的Service
s 列表,我可以通过调用添加和删除Car
s 而不会出现问题carViewModel.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>()
CarService.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 添加或删除到现有的Car
s。当我致电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。”
我可以通过从cars
列表中明确选择Car
来添加新的Services
。我没有收到任何错误,但 UI 没有更新;在应用重新启动之前,我看不到新添加的服务。
这样做没有错误,但 UI 不会更新。
carViewModel.addService(toCar: carViewModel.cars[1], serviceName: "Rotors")
如何正确查看、删除Service
s 并将其添加到现有Car
s?
编辑:根据Mahan
的请求添加了以下代码。
View 呈现 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()
【问题讨论】:
能否将您使用过NewServiceFormView
的视图包含在其中?
在父视图中我刚刚提出了NewServiceFormView
.sheet(isPresented: $newServiceFormIsPresented) NewServiceFormView(carViewModel: carViewModel, selectedCar: selectedCar)
谢谢。
@mahan - 查看更新的代码。谢谢。
【参考方案1】:
一个问题是如何观察 Realm 对象 - 请记住它们是底层的 ObjC 对象,因此您需要使用 Realm 观察者。所以这个
@ObservedObject var carViewModel: CarViewModel
应该是这样的
@ObservedRealmObject var carViewModel: CarViewModel
查看observedRealmObject的文档
另外,请记住,如果您正在观察结果,同样的事情也适用,使用
@ObservedResults
如documentation所示
【讨论】:
嗯,不幸的是,这并不像将@ObservedObject
替换为@ObservedRealmObject
那样简单。我目前正在使用 Swift/Combine @StateObject
和 ObservedObject
,所以我需要多玩一点,看看如何使用最近添加的 @ObservedResults
和 @ObservedRealmObject
包装器。谢谢!以上是关于如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象的主要内容,如果未能解决你的问题,请参考以下文章
如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?
SwiftUI:将视图与 VStack 中另一个视图的前缘和后缘对齐