A regression has been introduced with SwiftUI Menu in iOS 27 betas (still present in beta 6).
This regression prevents objects whose properties are bound to contained Menu items from being correctly deallocated.
In the example below, Player was immediately deallocated when the surrounding ModalView was dismissed on iOS 26 (or below):
import Observation
import SwiftUI
@Observable
final class Player {
var playbackSpeed: Double = 1
}
struct ModalView: View {
@State private var player = Player()
var body: some View {
Menu {
Picker(selection: $player.playbackSpeed) {
ForEach([0.5, 1, 1.5, 2], id: \.self) { speed in
Text("\(speed, specifier: "%g×")").tag(speed)
}
} label: {
Text("Speed")
}
.pickerStyle(.inline)
} label: {
Text("Menu")
}
}
}
This is not the case anymore on iOS 27 beta. The Player instance is not deallocated anymore.
A dedicated feedback (FB24486991) has been opened.
Hello @defagos
Thank you for reporting the issue and providing a clear example.
I made sure your report was seen by the relevant engineering team, it looks like they confirmed the issue is resolved in iOS 27 as well.
As a workaround for iOS 26 builds, use runtime version checks with #available in a condition that only runs in iOS 26, and try using a proxy @State property as the binding instead of binding directly to the @Observable object's property, then syncing changes back with .onChange.
if #available(iOS 27, *) {
// iOS 27-specific code
} else {
// Workaround code
}
Adjust the conditional statement to one that makes sense for your implementation.
Travis