SwiftUI TextField autofocus retains environment-injected objects after fullScreenCover dismissal with both ObservableObject and Observation

I am seeing a SwiftUI environment object remain alive after the view hierarchy that owns it has been dismissed.

The retained object is owned by @StateObject inside a fullScreenCover. A TextField presented deeper in that hierarchy receives focus through @FocusState.

After navigating back and dismissing the cover, the @StateObject does not deinitialize. The memory graph shows that system keyboard/input-assistant views retain a UITraitCollection, which retains a SwiftUIEnvironmentWrapper containing the environment object.

Environment

  • macOS 26.6.1 (25G76)
  • Xcode 26.6 (17F113)
  • iOS 26.5 Simulator
  • iPhone 11 26.6

Minimal reproduction

import Combine
import SwiftUI

final class DemoCoordinator: ObservableObject {
    let id = UUID()

    init() {
        print("[+] DemoCoordinator INIT \(id)")
    }

    deinit {
        print("[-] DemoCoordinator DEINIT \(id)")
    }
}

@main
struct FocusStateLeakApp: App {
    var body: some Scene {
        WindowGroup {
            RootView()
        }
    }
}

struct RootView: View {
    @State private var isFlowPresented = false

    var body: some View {
        Button("Present flow") {
            isFlowPresented = true
        }
        .fullScreenCover(isPresented: $isFlowPresented) {
            FlowContainer()
        }
    }
}

struct FlowContainer: View {
    @Environment(\.dismiss) private var dismiss
    @StateObject private var coordinator = DemoCoordinator()

    var body: some View {
        NavigationStack {
            NavigationLink("Push field screen") {
                FieldScreen()
            }
            .navigationTitle("Flow")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Close") {
                        dismiss()
                    }
                }
            }
        }
        .environmentObject(coordinator)
    }
}

struct FieldScreen: View {
    @State private var text = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        TextField("Type something", text: $text)
            .textFieldStyle(.roundedBorder)
            .focused($isFocused)
            .padding()
            .navigationTitle("Field")
            .onAppear {
                isFocused = true
            }
            .onDisappear {
                isFocused = false
            }
    }
}

Steps to reproduce

  1. Launch the application.
  2. Tap “Present flow”.
  3. Tap “Push field screen”.
  4. The TextField automatically becomes focused and the software keyboard appears.
  5. Navigate back.
  6. Tap “Close” to dismiss the full-screen cover.
  7. Observe the console or capture a memory graph.

Expected result:

After the full-screen cover is dismissed, FlowContainer and its @StateObject storage should be released. The following message should be printed:

[-] DemoCoordinator DEINIT ...

Actual result:

DemoCoordinator remains alive and its deinit is not called. The captured memory graph contains one DemoCoordinator.

The same behavior occurs after migrating the reproducer to the Observation framework.

Questions

  1. Is retaining the SwiftUI environment through keyboard-owned cached trait collections expected?
  2. Is there a supported way to prevent dismissed SwiftUI environments from being retained by the input-assistant hierarchy?
  3. Is this a known UIKit/SwiftUI issue for which a Feedback ID already exists?
  4. Should this be reported as a SwiftUI issue, UIKit issue, or Text Input issue in Feedback Assistant?

I can provide the minimal Xcode project and the captured .memgraph file if needed.

SwiftUI TextField autofocus retains environment-injected objects after fullScreenCover dismissal with both ObservableObject and Observation
 
 
Q