Nonetheless being fairly new to SwiftUI I wrestle to grasp if to make use of @Binding
in views solely or additionally in ViewModel lessons. Whereas there are a number of sources, which describe, that @Binding
is meant for use solely in Views
, there are a number of different sources and examples utilizing it in ViewModel
lessons as nicely.
Which info is appropriate? Ought to a ViewModel use @Binding
or solely @Revealed
and the view handles relaying adjustments from/to the ViewModel?
If it may be utilized in, ought to the ViewModel be used as @ObservedObject
or as @StateObject
?
I’ve created the next instance which compares all circumstances:
BindingViewModel
makes use of@Binding
to retailer a textual content propertyPublishedViewModel
makes use of@Revealed
to retailer a textual content property
ObservedBindingTextView
:BindingViewModel
as@ObservedObject
StateBindingTextView
:BindingViewModel
as@StateObject
ObservedPublishedTextView
:PublishedViewModel
as@ObservedObject
StatePublishedTextView
:PublishedViewModel
as@StateObject
Options 1, 3 and 4 appear all to work identically. Solely in Resolution 2 doesn’t deal with “incoming” textual content adjustments correctly. Right here each adjustments type inside and outdoors of this view are usually not utilized to its personal textual content view. Nevertheless adjustments from inside this view are appropriately utilized to all different views. Why?
Since Resolution 1, 3 and 4 work identically: Which one must be most popular? Is there an accurate resolution?
So far as I do know, the distinction between @ObservedObject
and @StateObject
is, that the later one is NOT destroyed / re-created everytime the view is re-drawn / re-created (appropriate?). Nevertheless, does this matter on this case?
struct SomeView: View {
class SomeViewModel: ObservableObject {
@Revealed var textual content = "Howdy, World!"
}
@ObservedObject personal var viewModel = SomeViewModel()
var physique: some View {
VStack {
Textual content(viewModel.textual content)
Button("Change Textual content") {
viewModel.textual content += "."
}
.padding(.backside, 60)
ObservedBindingTextView(textual content: $viewModel.textual content)
.padding(.backside, 30)
StateBindingTextView(textual content: $viewModel.textual content)
.padding(.backside, 60)
ObservedPublishedTextView(textual content: $viewModel.textual content)
.padding(.backside, 30)
StatePublishedTextView(textual content: $viewModel.textual content)
}
}
}
// Usung @Binding
class BindingViewModel: ObservableObject {
@Binding var textual content: String
init(textual content: Binding) {
_text = textual content
}
func changeText() {
textual content += "!"
}
}
struct ObservedBindingTextView: View {
@ObservedObject personal var viewModel: BindingViewModel
init(textual content: Binding) {
viewModel = .init(textual content: textual content)
}
var physique: some View {
VStack {
Textual content("Noticed Binding Textual content:n(viewModel.textual content)")
Button("Change Noticed Binding Textual content") {
viewModel.changeText()
}
}
}
}
struct StateBindingTextView: View {
@StateObject personal var viewModel: BindingViewModel
init(textual content: Binding) {
_viewModel = StateObject(wrappedValue: .init(textual content: textual content))
}
var physique: some View {
VStack {
Textual content("State Binding Textual content:n(viewModel.textual content)")
Button("Change State Binding Textual content") {
viewModel.changeText()
}
}
}
}
// Utilizing @Revealed
class PublishedViewModel: ObservableObject {
@Revealed var textual content: String
init(textual content: String) {
self.textual content = textual content
}
func changeText() {
textual content += "?"
}
}
struct ObservedPublishedTextView: View {
@Binding var textual content: String
@ObservedObject personal var viewModel: PublishedViewModel
init(textual content: Binding) {
_text = textual content
viewModel = .init(textual content: textual content.wrappedValue)
}
var physique: some View {
VStack {
Textual content("Noticed Publishe Textual content:n(viewModel.textual content)")
Button("Change Noticed Revealed Textual content") {
viewModel.changeText()
}
}
.onChange(of: textual content) { newText in
viewModel.textual content = newText
}
.onChange(of: viewModel.textual content) { newText in
textual content = newText
}
}
}
struct StatePublishedTextView: View {
@Binding var textual content: String
@StateObject personal var viewModel: PublishedViewModel
init(textual content: Binding) {
_text = textual content
_viewModel = StateObject(wrappedValue: .init(textual content: textual content.wrappedValue))
}
var physique: some View {
VStack {
Textual content("State Revealed Textual content:n(viewModel.textual content)")
Button("Change State Revealed Textual content") {
viewModel.changeText()
}
}
.onChange(of: textual content) { newText in
viewModel.textual content = newText
}
.onChange(of: viewModel.textual content) { newText in
textual content = newText
}
}
}