1

See the code below (BTW, List has the same issue):

enum Value: String, Equatable {
    case a = "a"
    case b = "b"
}

struct ContentView: View {
    @State var value: Value = .a
    @State var showSheet = false

    var body: some View {
        Form {
            Section {
                switch value {
                case .a:
                    Text("a")
                        .onTapGesture {
                            showSheet = true
                        }
                        .sheet(isPresented: $showSheet) {
                            Button("Set Value to .b") {
                                value = .b
                            }
                        }
                case .b:
                    Text("b")
                }
            }
        }
    }
}

To reproduce the issue, first click on text 'a' to bring up a sheet, then click on button in the sheet to change value. I'd expect the sheet should be dismissed automatically, because the view it's attached to is gone. But it isn't.

If I remove the Form, or replace it with, say, ScrollView, the behavior is as I expected. On other other hand, however, replacing it with List has the same issue (sheet isn't dismissed).

I'm thinking to file a FB, but would like to ask here first. Does anyone know if it's a bug or a feature? If it's a feature, what's the rationale behind it?

I'm currently using this workaround. Any other suggestions other than calling dismiss() in button handler are appreciated.

.onChange(of: value) { _ in
    showSheet = false
}

UPDATE: I think what I really wanted to ask is if there is an "ownership" concept for sheet? I mean:

  1. Does a sheet belongs to the view it's attached to and hence get dismissed when that view is destroyed?
  2. Or it doesn't matter where a sheet is defined in view hierarchy?

Since I never read about the ownership concept, I suppose item 2 is true. But if so, I don't understand why the sheet is dismissed automatically when I removed Form and Section in the above code.

0

1 Answer 1

1

Try this approach of adding showSheet = false just after value = .b in your sheet Button. Also move your .sheet(...) outside the Form, and especially if you are using a List.

 struct ContentView: View {
     @State var value: Value = .a
     @State var showSheet = false

     var body: some View {
         Form {
             Section {
                 switch value {
                 case .a:
                     Text("a")
                         .onTapGesture {
                             showSheet = true
                         }
                 case .b:
                     Text("b")
                 }
             }
         }
         .sheet(isPresented: $showSheet) {  // <-- here
             Button("Set Value to .b") {
                 value = .b
                 showSheet = false   // <-- here
             }
         }
     }
 }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer. That's my coding style too (moving sheet to the topmost and dismissing sheet explicitly. BTW, I was aware that dismiss() didn't work in this case, unless I introduced another view.) But sometimes it seems more natural to put sheet where it's needed. That's how I found the inconsistent behavior and hence the question. Your answer helped me to realize what I really wanted to ask. I have just updated my question and upvoted your answer, though I'll leave the question open for other answers. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.