pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
12.61k stars 1.46k forks source link

Deprecation advice for navigationDestination(store:destination) on macOS #2805

Closed johankool closed 9 months ago

johankool commented 9 months ago

Description

This is about a SwiftUI bug that happens on macOS. I report it here because the deprecation advices to use this code.

In NavigationDestination.swift it says:

  @available(
    macOS, deprecated: 9999,
    message:
      "Pass a binding of a store to 'navigationDestination(item:)' instead. For more information, see the following article: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/migratingto1.7#Replacing-navigation-view-modifiers-with-SwiftUI-modifiers]"
  )

Unfortunately this functionality is broken on macOS. If the recommended approach is used nothing happens on macOS when navigating.

// Does nothing on macOS 14
.navigationDestination(item: $store.scope(state: \.destination?.connect, action: \.destination.connect)) { store in
    ConnectView(store: store)
}

Staying with the deprecated approach, kinda works, but not really as it breaks perception/observation.

// Works, but purple warnings
.navigationDestination(store: store.scope(state: \.$destination.connect, action: \.destination.connect)) { store in
    ConnectView(store: store)
}

The workaround I found is that I need a bit of glue code in the store to calculate an isPresented binding and use the navigationDestination(isPresented:destination:) variant instead.

// Works with some glue code in the store to derive isConnecting from the current destination
.navigationDestination(isPresented: $store.isConnecting) {
    if let store = store.scope(state: \.destination?.connect, action: \.destination.connect) {
        ConnectView(store: store)
    }
}

Checklist

Expected behavior

No response

Actual behavior

No response

Steps to reproduce

No response

The Composable Architecture version information

1.8.0

Destination operating system

macOS 14.3.1

Xcode version information

Version 15.2 (15C500b)

Swift Compiler version information

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0
stephencelis commented 9 months ago

@johankool Another option is to use the polypill we define here:

https://pointfreeco.github.io/swift-composable-architecture/1.8.0/documentation/composablearchitecture/treebasednavigation#Backwards-compatible-availability

Just remove the deprecation availability.

Since this is an Apple bug I'm going to convert to a discussion. We can chat about modifying our deprecation message there, but my worry is I don't think we can validate every Apple API we point folks towards across every platform for every release.