Reputation: 2158
Here is my data model:
@MainActor
class TestModel: ObservableObject {
@Published private(set) var data = ""
private func randomAlphaNumericString(length: Int) -> String {
let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let allowedCharsCount = UInt32(allowedChars.count)
var randomString = ""
for _ in 0 ..< length {
let randomNum = Int(arc4random_uniform(allowedCharsCount))
let randomIndex = allowedChars.index(allowedChars.startIndex, offsetBy: randomNum)
let newCharacter = allowedChars[randomIndex]
randomString += String(newCharacter)
}
return randomString
}
func update() {
data = randomAlphaNumericString(length: 10)
}
}
And the application view is:
import SwiftUI
struct TestView: View {
@StateObject var model = TestModel()
var body: some View {
VStack {
TestSubView(textData: $model.data)
Button("Update") {
model.update()
}
}
}
}
where a subview is defined as follows:
import SwiftUI
struct TestSubView: View {
@Binding var textData: String
var body: some View {
Text("Data : \(textData)")
}
}
With this code I get a compilation error because of a private setter for a model field data. How can I stay with a private setter and get this binding to work? What is the correct pattern to follow?
Upvotes: 1
Views: 1112
Reputation: 77631
I think you don't need a @Binding
here at all. It looks like your TextSubView
is not updating the text. You just want to make sure that it updates when the text updates.
So change your view like this...
import SwiftUI
struct TestView: View {
@StateObject var model = TestModel()
var body: some View {
VStack {
TestSubView(textData: model.data)
Button("Update") {
model.update()
}
}
}
}
And your TextSubView like this...
import SwiftUI
struct TestSubView: View {
let textData: String
var body: some View {
Text("Data : \(textData)")
}
}
Doing this removes anything in the code that allows your view to update the text. Which you weren't doing anyway.
Upvotes: 1
Reputation: 119242
If none of the views can edit data
, then you don't need a binding. Just pass the value of data
as a let property. Any subviews contained within the TestView
will be reevaluated when the value changes anyway:
import SwiftUI
struct TestView: View {
@StateObject var model = TestModel()
var body: some View {
VStack {
TestSubView(textData: model.data)
Button("Update") {
model.update()
}
}
}
}
struct TestSubView: View {
let textData: String
var body: some View {
Text("Data : \(textData)")
}
}
Upvotes: 0