From the Apple's sessions and Tutorial we have two options to pass BindableObject to the views.
- Use declare
BindableObjectas a Source of truth in the top view in the hierarchy with@ObjectBindingwrapper and pass it to other views with@Bindingdeclared. - Use declare
BindableObjectas a Source of truth in the top view in the hierarchy with@EnviromentObjectwrapper, init top view with.enviroment(BindableObject)modifier and pass it to other views or with@Bindingdeclared, or using@EnviromentObject(in this caseBindableObjectwill be assigned automatically by SwiftUI and we do not need to pass it on init).
From Handling User Input tutorial if we have BindableObject with list of items in and we want to change one of the items on other view(or RowView or even separate screen) we need to:
- Pass the
BindableObjectto the deeper view using any of the ways above.- Pass the selected item to this view.
- Bind the property of the item with
BindingViewby finding the item inBindableObjectlist.
Some code to make the question clear:
Message model and BindableObject
struct Message: Identifiable {
var id: String
var toggle: Bool = true
}
class MessageStore: BindableObject {
let didChange = PassthroughSubject<MessageStore, Never>()
var messagesList: [Message] = testData {
didSet {
didChange.send(self)
}
}
}
MessageView that represents a list of items struct MessagesView
: View {
@EnvironmentObject var messageStore: MessageStore
var body: some View {
NavigationView {
List(messageStore.messagesList) { message in
NavigationButton(destination: Text(message.id)) {
MessageRow(message: message)
}
}
.navigationBarTitle(Text("Messages"))
}
}
}
MessageRow that has a Toggle to update the state of particular item in out BindableObject
struct MessageRow: View {
@EnvironmentObject var tags: MessageStore
var message: Message
var messageIndex: Int {
tags.messagesList.firstIndex { $0.id == message.id }!
}
var body: some View {
Toggle(isOn: self.$tags.messagesList[self.messageIndex].toggle) {
Text("Test toogle")
}
}
}
This approach is shown in the tutorial I mentioned above.
Question:
I wanted to pass Message separately as a @Binding to work with it in the child view directly, but I wasn't able to implement this.
I became a bit confused. Is it proper way to pass to any view(that should handle bindings) both the BindableObject and selected item to bind later the item from BindableObject using index? Is there any other way that will allow to pass not a full BindableObject but a part of it and bind this part(it should be Source of truth), in our case this part is Message?