I have a view that uses tab tab for iPhone layout (aka. "compact" size class) and a full-screen map with a floating overlay in lieu of the tab bar on iPad (aka. "regular" size class).
The map view's state (map, overlays, viewpoint, etc) are handled by an ObservableObject.
However, when the user puts the app in "slide over" or "split view" modes on iPad, the size class changes from "regular" to "compact", causing SwiftUI to re-render the hierarchy, destroy the old map view, and create a brand new MapView. This new mapview is then handed the same coordinator object.
This causes all kinds of trouble, since it seems most of the stuff are classes/reference types and it seems MapView does't support reusing those for more than a single MapView, methinks.
- If the mapview has overlays, I get a crash with "Object is already in use and may not be reused".
- If the mapview doesn't have overlays, the mapview won't crash, but also won't display the map after the size class change
I do want the app to preserve viewpoint and other state when changing size class.
Example:
struct ContentView: View {
@Environment(\.horizontalSizeClass) private var sizeClass
@StateObject private var coordinator = MapCoordinator()
var body: some View {
if sizeClass == .regular {
MyMapView(coordinator: coordinator)
.overlay(alignment: .topLeading) { Menu() }
} else {
TabView {
Menu()
.tabItem { Text("Menu") }
MyMapView(coordinator)
.tabItem { Text("Map") }
}
}
}
}
struct MyMapView: View {
@ObservedObject var coordinator: MapCoordinator
var body: some View {
MapView(
map: coordinator.map,
viewpoint: coordinator.viewPoint,
graphicsOverlays: coordinator.graphicsOverlays
)
.onScaleChanged(perform: coordinator.scaleChanged)
.onRotationChanged(perform: coordinator.rotationChanged)
}
}
Are my assumptions correct? Can I rework my app to fix these issues?