Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI @State and .sheet() ios13 vs ios14

Hello I am running into a problem here and I do not have a consistent behavior between my .sheet() view when running on ios13 or ios14

I got a view like this :

@State private var label: String = "" 
@State private var sheetDisplayed = false
///Some code
var body: some View {
   VStack {
      Button(action: {
         self.label = "A label"
         self.isDisplayed = true
      }) {
           Text("test")
       }
   }.sheet(isPresented: $sheetDisplayed, onDismiss: {
        self.label = ""
    }) {
        Text(self.label)
       }
 }

On ios 13 this work as expected btn click -> set label -> call sheet -> display "A label" in a Text view.

On ios14 I got an empty string in self.label when in sheet closure, hence it does not display anything.

Did I missed something ? Is it an iOS 14 bug or did I had it wrong on ios13 and that got corrected.

PS: I have a couple of other variables that are passed in the closure I simplified it.

like image 504
FitzChill Avatar asked Sep 17 '20 22:09

FitzChill


2 Answers

Your code have expectation of view update/creation order, but in general it is undefined (and probably changed in iOS 14).

There is explicit way to pass information inside sheet - use different sheet creator, ie. .sheet(item:...

Here is working reliable example. Tested with Xcode 12 / iOS 14

struct ContentView: View {
    @State private var item: Item?

    struct Item: Identifiable {
        let id = UUID()
        var label: String = ""
    }

    var body: some View {
        VStack {
            Button(action: {
                self.item = Item(label: "A label")
            }) {
                Text("test")
            }
        }.sheet(item: $item, onDismiss: {
            self.item = nil
        }) {
            Text($0.label)
        }
    }
}
like image 158
Asperi Avatar answered Oct 19 '22 13:10

Asperi


This is some really strange behaviour in iOS 14, which doesn't appear to be documented.

Using the other answer here and the comment on this thread, I used @Binding to solve the issue as it seemed the cleanest and most SwiftUI-esq solution.

I have no idea why this behaviour has changed, and it seems less intuitive than before, so I'm assuming its a bug!

An example:

struct MainView: View {
    @State private var message = ""
    @State private var showSheet = false

    var body: some View {
        Button(action: {
            self.message = "This will display the correct message"
            self.showSheet = true
        }, label: {
            Text("Test Button")
        })
        .sheet(isPresented: self.$showSheet) {
            SheetView(message: self.$message)
        }
    }
}

struct SheetView: View {
    @Binding var message: Int

    var body: some View {
        Text(self.message)
    }
}
like image 4
Othyn Avatar answered Oct 19 '22 13:10

Othyn