I'm trying to display a checklist in SwiftUI which is stored in SwiftData:
@Model
class ChecklistItem: Identifiable, ObservableObject {
let id = UUID()
var title: String
var isChecked: Bool
var sortOrder: Int
init(title: String, isChecked: Bool, sortOrder: Int) {
self.title = title
self.isChecked = isChecked
self.sortOrder = sortOrder
}
}
@Model
class ChecklistModel: Identifiable, Hashable, ObservableObject {
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func == (lhs: ChecklistModel, rhs: ChecklistModel) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
let id = UUID()
var title: String
@Relationship var items: [ChecklistItem]
init(title: String, items: [ChecklistItem]) {
self.title = title
self.items = items
}
}
ScrollView {
ForEach(checklist.items.sorted(by: { $0.sortOrder < $1.sortOrder }), id: \.self) { item in
//ForEach(checklist.items.sorted(by: {$0.sortOrder < $1.sortOrder}).indices, id: \.self) { index in
// let item = checklist.items[index]
// if I do it this way, the items are not sorted in the correct order
HStack {
Toggle(item.title, isOn: item.$isChecked)
.toggleStyle(CheckboxToggleStyle())
Text("\(item.sortOrder)")
}
}
But if I try it the uncommented way so that the sorting works correctly, I get this error:
Initializer 'init(_:isOn:)' requires that 'Binding<Subject>' conform to 'StringProtocol'
So what's the solution here? How can I sort these items correctly in the view and also bind the Toggle
value to the model?
Assuming checklist
is one ChecklistModel
, try this approach using a @Bindable
as shown in the example code, together with the updated @Model class
without the ObservableObject
.
Note, @Model
macro makes the class conform to Observable, Hashable and Identifiable.
ScrollView {
ForEach(checklist.items.sorted(by: { $0.sortOrder < $1.sortOrder })) { item in
@Bindable var item = item // <-- here
HStack {
Toggle(item.title, isOn: $item.isChecked) // <-- here
.toggleStyle(.automatic)
Text("\(item.sortOrder)")
}
}
}
@Model
class ChecklistItem { // <-- here
var title: String
var isChecked: Bool
var sortOrder: Int
init(title: String, isChecked: Bool, sortOrder: Int) {
self.title = title
self.isChecked = isChecked
self.sortOrder = sortOrder
}
}
@Model
class ChecklistModel { // <-- here
var title: String
@Relationship var items: [ChecklistItem]
init(title: String, items: [ChecklistItem]) {
self.title = title
self.items = items
}
}
See this link SwiftData with model, it gives you some good examples of how to use SwiftData
with @Model
to
persist data in your app.