Hi,
when using an ForEach within an ScrollView the UI does not get updated if the ObservedObject, which is used in ForEach, changes. If the ForEach is not embedded in a ScrollView the update works.
IMHO the ForEach within the ScrollView should work, or am I wrong?
To illustrate the issue here's some example coding to paste in an (iOS) Playground.
import PlaygroundSupport
import SwiftUI
struct User: Hashable {
var name: String
}
typealias Users = [User]
let usersData = [
User(name: "Alpha"),
User(name: "Beta"),
User(name: "Gamma"),
]
class UserViewModel: ObservableObject {
@Published var users: Users = []
func get() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
print("Update")
self.users = usersData
}
}
}
// If the ScrollView is present nothing is shown after the model is updated.
// If a screen refresh is triggered (for example when running this on device and switch
// from portrait to landscape the UI shows up.
struct ContentView: View {
@ObservedObject var user = UserViewModel()
var body: some View {
ScrollView { // comment scrollview out and it works
ForEach(user.users, id: \.self) { user in
Text("\(user.name)")
}
}
.onAppear {
self.user.get() // to simulate model update
}
}
}
PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())
Thanks for your Feeback!
Cheers, Michael
To answer to myself with a workaround (in case anybody has the same issue and is looking for one), please see below:
Still I think the original code should work, right?
It seems that a ScrollView can't can't be initially empty:
struct ContentView: View {
@ObservedObject var user = UserViewModel()
var body: some View {
Group {
if user.users.isEmpty {
EmptyView()
} else {
ScrollView { // comment scrollview out and it works
ForEach(user.users, id: \.self) { user in
Text("\(user.name)")
}
}
}
}
.onAppear {
self.user.get() // to simulate model update
}
}
}