PresentationLink broken in Xcode 11 beta 3
PresentationLink
(in SwiftUI
) seems to be broken in Xcode 11 beta 3.
It succeeds in presenting a modal view controller the first time, but stops working thereafter.
As noted in this StackOverflow post, this seems to occur when embedding a PresentationLink
within a NavigationView
, with the following warning printed to console:
[WindowServer] display_timer_callback: unexpected state (now:1abc3d3ccc7 < expected:1abc3d91a0f)
This bug has existed since Xcode 11 beta 1 (back when PresentationLink
was called PresentationButton
), which is quite alarming given the fact that we’re on beta 3 now.
I’ve written a quick and dirty workaround for this:
private enum SetPresentedViewKey: EnvironmentKey {
static var defaultValue: (AnyView?) -> () {
fatalError()
}
}
private extension EnvironmentValues {
var setPresentedView: (AnyView?) -> () {
get {
self[SetPresentedViewKey.self]
} set {
self[SetPresentedViewKey.self] = newValue
}
}
}
/// A replacement for the buggy (as of Xcode 11 b3) `PresentationLink`.
public struct PresentationLink2<Destination: View, Label: View>: View {
public let destination: Destination
public let label: Label
@Environment(\.setPresentedView) private var setPresentedView
@State private var presentedView: AnyView? = nil
public init(destination: Destination, @ViewBuilder _ label: () -> Label) {
self.destination = destination
self.label = label()
}
private struct _Body<Destination: View, Label: View>: View {
@Environment(\.setPresentedView) private var setPresentedView
let destination: Destination
let label: Label
init(destination: Destination, label: Label) {
self.destination = destination
self.label = label
}
var body: some View {
Button(action: present, label: { label })
}
func present() {
setPresentedView(AnyView(destination))
}
}
public var body: some View {
_Body(destination: destination, label: label)
.environment(\.setPresentedView, { self.presentedView = $0 })
.presentation(presentedView.map {
Modal($0, onDismiss: { self.presentedView = nil })
})
}
}
Simply swap out PresentationLink
for PresentationLink2
, and your modal view presentations should start working consistently.