Reputation: 2811
From the Apple's sessions and Tutorial we have two options to pass BindableObject to the views.
BindableObject
as a Source of truth in the top view in the hierarchy with @ObjectBinding
wrapper and pass it to other views with @Binding
declared.BindableObject
as a Source of truth in the top view in the hierarchy with @EnviromentObject
wrapper, init top view with .enviroment(BindableObject)
modifier and pass it to other views or with @Binding
declared, or using @EnviromentObject
(in this case BindableObject
will 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:
BindableObject
to the deeper view using any of the ways above.
BindingView
by finding the item in BindableObject
list.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
?
Upvotes: 2
Views: 889
Reputation: 7
I think you are overcomplicating it. It seems that all you need is a toggle value in your message. Try this:
var body: some View {
NavigationView {
List(messageStore.messagesList) { message in
NavigationButton(destination: Text(message.id)) {
MessageRow(isTogged: $message.toggle)
}
}
.navigationBarTitle(Text("Messages"))
}
}
struct MessageRow: View {
@Binding var isToggled: Bool
var body: some View {
Toggle(isOn: self.isToggled) {
Text("Test toogle")
}
}
}
Upvotes: 0