loading...

I had a bug with ForEach and Range in my SwiftUI code

vorahsa profile image Jaakko Kangasharju ・2 min read

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.

Posted on by:

vorahsa profile

Jaakko Kangasharju

@vorahsa

I'm a generalist developer, preferring to have some skills in a variety of areas to being really good at only a few. I need to see how a technology solves real problems to really understand it.

Discussion

pic
Editor guide