Post

Replies

Boosts

Views

Activity

Why do I get an error when deleting data from SwiftUI List and Realm?
Hi all,I know this is may not be the right forum to post questions about Realm but my issue has to do with the nature of how SwiftUI works.Has anyone been able to successfully integrate Realm with SwiftUI, especially deleting records/rows from a SwiftUI List? I have tried a few different things but no matter what I do I get the same error. After reading some related threads I found out that other people have the same issue but I refuse to think that there is no current solution to integrate Realm with SwiftUI.The following code successfully presents all of the items from Realm in a SwiftUI List, I can create new ones and they show up in the List as expected, my issues is when I try to delete records from the List by either manually pressing a button or by left-swiping to delete the selected row, I get an Index is out of bounds error.Here is my code.Realm Model:class Dog: Object { @objc dynamic var name = "" @objc dynamic var age = 0 @objc dynamic var createdAt = NSDate() @objc dynamic var userID = UUID().uuidString override static func primaryKey() -> String? { return "userID" } }SwiftUI Code:class BindableResults: ObservableObject where Element: RealmSwift.RealmCollectionValue { var results: Results private var token: NotificationToken! init(results: Results) { self.results = results lateInit() } func lateInit() { token = results.observe { [weak self] _ in self?.objectWillChange.send() } } deinit { token.invalidate() } } struct DogRow: View { var dog = Dog() var body: some View { HStack { Text(dog.name) Text("\(dog.age)") } } } struct ContentView : View { @ObservedObject var dogs = BindableResults(results: try! Realm().objects(Dog.self)) var body: some View { VStack{ List{ ForEach(dogs.results, id: \.name) { dog in DogRow(dog: dog) }.onDelete(perform: deleteRow ) } Button(action: { try! realm.write { realm.delete(self.dogs.results[0]) } }){ Text("Delete User") } } } private func deleteRow(with indexSet: IndexSet){ indexSet.forEach ({ index in try! realm.write { realm.delete(self.dogs.results[index]) } }) } }ERRORTerminating app due to uncaught exception ‘RLMException’, reason: ‘Index 23 is out of bounds (must be less than 23).’Of course, the 23 changes depending on how many items are in the Realm database, in this case, I had 24 records when I swiped and tapped the delete button.
4
0
3.7k
Apr ’22
What's the recommended code structure to manage apps with MVVM+SwiftUI+CoreData
I have a SwiftUI app with 3 Core Data entities, Car, CarService and ServiceRecord where Car has many carServices and each CarService has many serviceRecords. Everything is working fine but I'm not sure what's the most common MVVM practice. As you can see in the following example I'm using CoreDataViewModel to fetch data from Core Data and then I pass it around all SwiftUI views, at the moment I don't have a ViewModel for the view's logic (the logic is currently inside of each view) but that's something I would like to incorporate, but I'm not sure what would be the best way to do that. I'm thinking about the two following option... Create a view model for each view (CarViewModel, ServicesViewModel and RecordsViewModel) to handle ONLY the view's logic and leave the existing CoreDataViewModel as is. Create a view model for each view, CarViewModel, ServicesViewModel and RecordsViewModel to handle the logic for each view and move the CoreData quests to each of the view models respectably and basically delete CoreDataViewModel altogether since now the core data related will live inside each view model. Which of the two options above makes more sense for an MVVM app? In general, can someone please share how you usually structure your code when using MVVM + CoreData + SwiftUI? CoreDataManager class CoreDataManager{ static let instance = CoreDataManager() lazy var context: NSManagedObjectContext = { return container.viewContext }() lazy var container: NSPersistentContainer = { return setupContainer() }() func setupContainer()->NSPersistentContainer{ // code to setup container... return container } func save(){ do{ try context.save() }catch let error{ print("Error saving Core Data. \(error.localizedDescription)") } } } CoreDataViewModel class CoreDataViewModel: ObservableObject{ let manager: CoreDataManager @Published var cars: [Car] = [] @Published var carServices: [CarService] = [] @Published var serviceRecords: [ServiceRecord] = [] init(coreDataManager: CoreDataManager = .instance){ self.manager = coreDataManager // getCars() etc. } // CREATIONS func addCar(name:String){} func addService(name:String, cost: Double){} func createRecord(name:String, cost: Double){} // DELETES func deleteCar(){} func deleteCarService(){} func deleteServiceRecord(){} // UPDATES func updateCar(){} func updateService(){} // GETS func getCars(){} func getServices(){} func getRecords(){} func save(){ self.manager.save() } } SwiftUI Views CarsView struct CarsView: View { @StateObject var coreDataViewModel = CoreDataViewModel() var body: some View { NavigationView{ VStack{ List { ForEach(coreDataViewModel.cars) { car in } } } } } } ServicesView struct ServicesView: View { @ObservedObject var coreDataViewModel:CoreDataViewModel var body: some View { NavigationView{ VStack{ List { ForEach(coreDataViewModel.carServices) { service in } } } } } } RecordsView struct RecordsView: View { @ObservedObject var coreDataViewModel: CoreDataViewModel var body: some View { NavigationView{ VStack{ List { ForEach(coreDataViewModel.serviceRecords) { record in } } } } } } Thanks!
2
1
3.7k
May ’22