I have a side project for iOS, and since it's a side project, I thought to try SwiftUI for the UI. There's some complexity because the UI isn't exactly traditional, but overall, I've been happy with SwiftUI.
But when Xcode 11.4 was released, the app wouldn't work properly. Some, but not all, parts of the UI weren't updating anymore when state changed. For a while, I stayed on 11.3 so I could work on the functionality, but as time passed, it became evident that this wasn't a problem with Xcode or iOS, it was something in my code.
Mostly, I thought that I had messed up with the bindings so that the UI wasn't observing my presentation layer properly. No luck there, nothing I tried would work. After a lot of frantic Web searching, I eventually found the answer in the comments to an unrelated blog post.
My code looked something like this
struct MainView: View {
@Binding var names: [[String?]]
var body: some View {
VStack {
ForEach(0..<self.names.count) { nameIndex in
NamesView(self.$names[nameIndex])
}
}
}
}
The problem is that ForEach
has three init
methods,
init(Data, content: (Data.Element) -> Content)
init(Range<Int>, content: (Int) -> Content)
init(Data, id: KeyPath<Data.Element, ID>, content: (Data.Element) -> Content)
and using it like I did picks the second one, with the Range
parameter. This method assumes that the range doesn't change, which is true in my case, but it also seems to assume that the content views don't change, at least from Xcode 11.4 onward. Maybe this is a bug, maybe it's intended behavior, I can't tell from the documentation.
When I had finally discovered the problem, the fix was simple enough. I changed the ForEach
to
ForEach(0..<self.names.count, id: \.self) { nameIndex in
NamesView(self.$names[nameIndex])
}
which picks the third init
method of ForEach
, and allows updates of the views.
Top comments (1)
I created an account just to say THANK YOU!!!! I had exactly the same problem, what a stupidly easy fix. I hate SwiftUI for making solutions like this so hard to find ...