I am making a SwiftUI Mac app that uses navigation split view and the Observation framework. The split view has a sidebar list, a detail view, and a selection
property to store the selected item in the list. I set the initial selection to the first item in the list using the .onAppear
modifier.
When I select an item from the list, I get the desired behavior. The detail view shows the contents of the selected item. But the selection
property’s value changes to nil. Because selection
is nil, I am unable to remove items from the list.
Model Code
struct Wiki {
var pages: [Page] = []
}
@Observable
class Page: Identifiable, Equatable, Hashable {
let id = UUID()
var title: String = "Page"
var text: String
static func == (lhs: Page, rhs: Page) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(title)
hasher.combine(text)
}
}
Split View Code
struct ContentView: View {
@Binding var wiki: Wiki
@State private var selection: Page? = nil
var body: some View {
NavigationSplitView {
PageList(wiki: $wiki, selection: $selection)
.navigationSplitViewColumnWidth(ideal: 192)
} detail: {
if let selection {
PageView(page: selection)
} else {
Text("Select a page to view its contents.")
}
}
.onAppear {
selection = wiki.pages.first
}
}
}
List Code
struct PageList: View {
@Binding var wiki: Wiki
@Binding var selection: Page?
var body: some View {
VStack {
Text("Pages")
.font(.title)
List($wiki.pages, selection: $selection) { $page in
NavigationLink {
PageView(page: page)
} label: {
TextField("", text: $page.title)
}
}
.padding()
}
}
}
Detail View Code
struct PageView: View {
@Bindable var page: Page
var body: some View {
TextEditor(text: $page.text)
}
}
I tried changing selection
in the list view from @Binding
to @Bindable
, but I get the following build error:
'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable
What fix do I have to make to get the selection
property to not be nil when I select an item from the list?