Hello guys, given the following implementation of a RealmDatamanager and some basic View, I end up with this code; similarly, after asking chatgpt, I ended up with the exact same example code.
It keeps crashing when deleting an element from the database.
User.swift
import Foundation
import RealmSwift
class User: Object, Identifiable {
@objc dynamic var id: String = UUID().uuidString
@objc dynamic var name: String = ""
@objc dynamic var age: Int = 0
override static func primaryKey() -> String? {
return "id"
}
}
RealmDatabaseManager.swift
import Foundation
import RealmSwift
import Combine
class RealmDatabaseManager: ObservableObject {
private var realm: Realm
private var cancellables: Set<AnyCancellable> = []
@Published var users: [User] = []
init() {
realm = try! Realm()
fetchUsers()
observeUsers()
}
private func fetchUsers() {
users = Array(realm.objects(User.self))
}
private func observeUsers() {
realm.objects(User.self)
.observe { [weak self] (changes: RealmCollectionChange) in
DispatchQueue.main.async {
switch changes {
case .initial, .update:
self?.fetchUsers()
default:
break
}
}
}
}
func addUser(_ user: User) {
do {
try realm.write {
realm.add(user)
}
} catch {
print("Error adding user: \(error)")
}
}
func updateUser(_ user: User, withName name: String, age: Int) {
do {
try realm.write {
user.name = name
user.age = age
}
} catch {
print("Error updating user: \(error)")
}
}
func deleteUser(_ user: User) {
do {
try realm.write {
realm.delete(user)
}
} catch {
print("Error deleting user: \(error)")
}
}
}
UserRowView.swift
import SwiftUI
struct UserRowView: View {
let user: User
var body: some View {
HStack {
if !user.isInvalidated { // Add this check
VStack(alignment: .leading) {
Text(user.name)
.font(.headline)
Text("Age: \(user.age)")
.font(.subheadline)
}
}
}
}
}
UserListView.swift
import SwiftUI
struct UserListView: View {
@ObservedObject private var userManager = RealmDatabaseManager()
var body: some View {
NavigationView {
List {
ForEach(userManager.users) { user in
if !user.isInvalidated { // Add this check
NavigationLink(destination: UserDetailView(user: user, userManager: userManager)) {
UserRowView(user: user)
}
}
}
}
.navigationTitle("Users")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: addUser) {
Image(systemName: "plus")
}
}
}
}
}
private func addUser() {
let newUser = User()
newUser.name = "New User"
newUser.age = 0
userManager.addUser(newUser)
}
}
UserDetailView.swift
import SwiftUI
struct UserDetailView: View {
let user: User
let userManager: RealmDatabaseManager
@State private var name: String = ""
@State private var age: String = ""
@Environment(\.presentationMode) var presentationMode
var body: some View {
Form {
Section {
TextField("Name", text: $name)
TextField("Age", text: $age)
.keyboardType(.numberPad)
}
Section {
Button("Save") {
if let ageInt = Int(age), !user.isInvalidated {
userManager.updateUser(user, withName: name, age: ageInt)
}
presentationMode.wrappedValue.dismiss()
}
Button("Delete") {
if !user.isInvalidated {
userManager.deleteUser(user)
presentationMode.wrappedValue.dismiss()
}
}
.foregroundColor(.red)
}
}
.onAppear {
if !user.isInvalidated {
name = user.name
age = String(user.age)
} else {
presentationMode.wrappedValue.dismiss()
}
}
.navigationBarTitle(user.isInvalidated ? "" : user.name, displayMode: .inline)
}
}
App.swift
import SwiftUI
@main
struct SomeTestApp: App {
var body: some Scene {
WindowGroup {
UserListView()
}
}
}
I am starting to give up on Realm. Working with it with no backtrace on the error is becoming very frustrating.
This code above, by simply adding it in a new swift/swiftui project, will compile and replicate the issue. (do not forget to add the realmswift repo in the package depedency)
Do you have any recommendations to improve that code not to make it crash?
I checked the other existing topics, with for example using thaw. should I add the thaw to the delete function in the realm manager? it seems weird, why wouldn’t it be by default instead of crashing?
Edit 1: I tried by changing my deleteUser
function to the following
func deleteUser(_ user: User) {
guard let thawedItem = user.thaw() else {
return
}
if thawedItem.isInvalidated == false { //ensure it's a valid item
let thawedRealm = thawedItem.realm! //get the realm it belongs to
do {
try thawedRealm.write {
thawedRealm.delete(thawedItem)
}
} catch {
print("Error deleting user: \(error)")
}
}
}
still crashing