SwiftUI Tutorial PresentationButton Bug

2020-02-01 03:14发布

问题:

I started to experiment with the new SwiftUI framework, announced on the WWDC 2019 and started the tutorial on https://developer.apple.com/tutorials/swiftui.

Now I came to the point where to connect the Profile to the HomeScreen via the PresentationButton. More precisely I am talking about this section of code in Home.swift:

            .navigationBarItems(trailing:
                PresentationButton(
                    Image(systemName: "person.crop.circle")
                        .imageScale(.large)
                        .accessibility(label: Text("User Profile"))
                        .padding(),
                    destination: ProfileHost()
                )
            )

When I first click on the button the Profile Sheet appears just fine, but when I dismiss it and then click on the button again nothing happens.

Does anyone know why this is the case ?

Thanks in advance

回答1:

It looks like a bug in SwiftUI. It is probably linked to the fact that onDisappear is never called. You can verify that by adding

.onAppear{
  print("Profile appeared")
}.onDisappear{
  print("Profile disappeared")
}

to ProfileHost view. It would make sense that an appear should be balanced by a disappear for the dismissal to be complete.

It is possible to work around it by implementing a function that returns a PresentationButton that "depends" on a state variable.

@State var profilePresented: Int = 0
func profileButton(_ profilePresented: Int) -> some View {
  return PresentationButton(
    Image(systemName: "person.crop.circle")
      .imageScale(.large)
      .accessibility(label: Text("User Profile"))
      .padding(),
    destination: ProfileHost(),
    onTrigger: {
      let deadlineTime = DispatchTime.now() + .seconds(2)
      DispatchQueue.main.asyncAfter(deadline: deadlineTime, execute: {
        self.profilePresented += 1
      })
  })
}

And replace

.navigationBarItems(trailing:
      PresentationButton(
          Image(systemName: "person.crop.circle")
              .imageScale(.large)
              .accessibility(label: Text("User Profile"))
              .padding(),
          destination: ProfileHost()
      )
  )

with

.navigationBarItems(trailing: self.profileButton(self.profilePresented))

I highly recommend to not use this "solution" and just report the bug to Apple.



回答2:

The most simple way to solve this issue is by leaving the destination: parameter on its own and have the Image object in the curly braces:

PresentationButton(destination: ProfileHost()) {
    Image(systemName: "person.crop.circle")
        .imageScale(.large)
        .accessibility(label: Text("User Profile"))
        .padding()
}


回答3:

This was fixed in Beta 3. I also had the same issue, where PresentationButton (now PresentationLink) was only firing once when embedded in .navigationBarItems.



回答4:

This was a bug resolved in Xcode 11 Beta2: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_beta_2_release_notes.

With the updated API the following should work:

PresentationButton(destination:ProfileHost()) {
    Image(systemName: "person.crop.circle")
    .imageScale(.large)
    .accessibility(label: Text("User Profile"))
    .padding()
}