Hey all,
I’m having some issues with Realm + SwiftUI.
Models
My app has 4 models:
Household
final class Household: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: String = UUID().uuidString
@Persisted var name: String
@Persisted var users = RealmSwift.List<String>()
@Persisted var lists = RealmSwift.List<List>()
@Persisted var itemTypes = RealmSwift.List<ItemType>()
}
List
final class List: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: String = UUID().uuidString
@Persisted var name: String
@Persisted var listItems = RealmSwift.List<ListItem>()
}
ItemType
final class ItemType: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: String = UUID().uuidString
@Persisted var name: String
@Persisted var categories = RealmSwift.List<String>()
}
ListItem
final class ListItem: EmbeddedObject, ObjectKeyIdentifiable {
@Persisted var _id: String = UUID().uuidString
@Persisted var itemType: ItemType?
@Persisted var quantity: String?
@Persisted var note: String?
}
Essentially I have set it up so that a user belongs to a household (the household ID is the partition key), each household has 1 or more lists and 1 or more itemTypes. A list contains a collection of listItems and each listItem is assigned an item type.
I’ve chosen this model so that when a user updates the name or categories associated with an itemType, all listItems assigned that itemType will also be updated.
My View
Here is a simplified version of my views:
ListsView
struct ListsView: View {
@StateRealmObject var household: Household #This is passed in from a parent view where the user selects a household. At the moment it only shows 1 household (since household ID is the partition key, but I will fix this up later once the rest of the app is working as intended)
var body: some View {
VStack {
SwiftUI.List {
ForEach(household.lists) { list in
NavigationLink(destination: ListDetailView(household: household, list: list)) {
Text(list.name)
}.font(.body)
}
}
.navigationBarTitle("Your Lists")
}
}
}
ListDetailView
struct ListDetailsView: View {
@StateRealmObject var household: Household
@StateRealmObject var list: List
@State var itemName: String = ""
var body: some View {
VStack {
SwiftUI.List {
ForEach(list.listItems, id: \.id) { item in
if let itemType = item.itemType {
ListItemView(listItem: item, itemType: itemType)
}
}.onDelete(perform: $list.listItems.remove)
}
Spacer()
HStack {
TextField("Enter an item name", text: $itemName)
TsButton(
action: {
onInsertItem(name: itemName)
},
text: "add item"
)
}
}
.navigationTitle(list.name)
}
/**
When a user inserts an item, check if an itemType already exists for the given name.
If an itemType with this name already exists, assign that itemType to a new listItem
and assign that listItem to the currently viewed list.
If an itemType does not exist with a given name, create a new one, assign the new itemType
to a new listItem and assign that listItem to the currently viewed list.
*/
func onInsertItem(name: String) {
if let itemType = household.itemTypes.first(where: { other in other.name == name }) {
// Item type with this name already exists
let listItem = ListItem()
listItem.itemType = itemType
$list.listItems.append(listItem)
} else {
// No item type exists for this name, so create a new one
let itemType = ItemType();
itemType.name = name
$household.itemTypes.append(itemType)
let listItem = ListItem()
listItem.itemType = itemType
$list.listItems.append(listItem)
}
}
}
Problem
I am getting the following error whenever I try to add a new listItem for an itemType that already exists:
Object is already managed by another Realm. Use create instead to copy it into this Realm.
. If I add a listItem for a new itemType, it works as expected.
I have tried the following and the error becomes Cannot modify managed RLMArray outside of a write transaction.
:
let listItem = ListItem()
listItem.itemType = itemType
$list.listItems.wrappedValue.append(listItem)
I have also tried opening a write transaction against the realm referenced by the list, and I get an error about the primary key of the itemType not being unique.
When I inspect the itemType and list they both contain a reference to the same realm object. So I am not sure what may be going wrong.
Does anyone have any ideas?