iosswiftuiswiftui-stateswiftui-sheet

LazyGrid with onTap gesture on items does not work as intended with sheet presentation


I am trying to understand @State. Ignoring the view model in the picture, I am trying to present a view modally with sheet modifier on tapping any item on my lazygrid. For some reason an empty view is presented as the selected item is always nil for some reason.

This is how my state properties looks

@State private var selectedFollower : Follower? = nil
@State var showFollowerDetail = false

This is the presentation on list

ForEach(followers, id: \.self) { follower in
      GridCells(follower: follower)
           .onTapGesture {
                  selectedFollower = follower
                  showFollowerDetail = true
           }
}

And this is the sheet modifier

.sheet(isPresented: $showFollowerDetail, content: {
      if let selectedFollower{
            UserInfoView(follower: selectedFollower)
      }
})

Solution

  • (Although it seems like an internal bug to me), it happens when you try to define a separate flag State and manually manage it and sometimes it gets out of sync somehow (like when there is a race between the render engine and the closure capture).

    To work around it, you can drive the Binding<Bool> directly from the source of truth to make sure it is always in sync:

    @State private var selectedFollower: Follower?
    var showFollowerDetail: Binding<Bool> {
        .init {
            selectedFollower != nil
        } set: {
            guard !$0 else { return }
            selectedFollower = nil
        }
    }
    

    Or simply use the other initializer that accepts an optional as recommended:

    .sheet(item: $selectedFollower) { selectedFollower in
         UserInfoView(follower: selectedFollower)
    }