I'm trying to store this model using SwiftData
in order to display it within List
with children tree.
However List
requires its children to be of the same type as the parent and that's an issue for SwiftData
as it seems. Immediately after I build and run following code I get an "Unknown related type error" fatal within the model macro.
Model:
@Model final class LibraryItem: Identifiable {
@Attribute(.unique) let id: UUID
var name: String
...
var subMenuItems: [LibraryItem]?
}
Error:
I build the tree using a few recursive functions to reflect the file system hierarchy of given URL. This is my List
:
List(
libraryItems,
children: \.subMenuItems,
selection: Binding(
get: {
selectedLibraryItemId
},
set: { ids, _ in
selectionHandler(ids)
}
)
) { item in
Text(item.name)
}
And this is how I initialise the ModelContainer
:
init() {
let schema = Schema([LibraryItem.self])
let config = ModelConfiguration(schema: schema, groupContainer: .identifier("antonincharvat.com.appName"))
do {
let container = try ModelContainer(for: schema, configurations: config)
self.libraryItemsModelContainer = container
} catch {
fatalError("Couldn't create ModelContainer")
}
}
Is there any way for this to work? I tried to use computed property as the children collection, but List
initialises all its children at once causing this approach unusable.
As I see it there are two things you need to change in your model to make this work, create a second property for the inverse of the relationship and also use the @Relationship
wrapper for one of the relationship properties to exclusively point out what the key path is to the opposite property of the relationship.
This is what my LibraryItem
model ended up like
@Model final class LibraryItem: Identifiable {
@Attribute(.unique) let id: UUID
var name: String
var subMenuItems: [LibraryItem]?
@Relationship(deleteRule: .nullify, inverse: \LibraryItem.subMenuItems)
var parentItem: LibraryItem?
init(name: String) {
self.id = UUID()
self.name = name
}
}