You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 17中位置更新引发Toolbar菜单意外消失问题(关联菜单内容)

iOS 17位置更新导致Toolbar菜单意外关闭的问题

问题描述

我的App需要追踪用户位置,但每次locationManager发送位置更新时,若Toolbar菜单处于展开状态就会被意外关闭。奇怪的是,若菜单按钮的操作是空实现或仅包含print语句则无此问题,一旦调用实际方法(哪怕是空方法help()),下次UI更新时菜单就会消失。

环境信息

  • iOS: 17.0
  • Xcode: Version 15.0 beta 3
  • 后台模式: Location updates
  • 隐私权限配置: Privacy - Location When In Use Usage Description = You are being watched!

相关代码

import SwiftUI

@main
struct DetectHelpApp: App {

    var locationManager = LocationManager()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(locationManager)
        }
    }
}

import MapKit

struct ContentView: View {

    @Environment(LocationManager.self) var locationManager

    @State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.556000, longitude: -0.279511), latitudinalMeters: 1000, longitudinalMeters: 1000))

    var body: some View {
        NavigationStack {
            Map(position: $cameraPosition) {
                UserAnnotation()
            }
            .onChange(of: locationManager.lastLocation) { oldValue, newValue in
                print(locationManager.lastLocation)
                withAnimation() {
                    cameraPosition = .region(MKCoordinateRegion(center: newValue.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000))
                }
            } // onChange - end
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Menu("Menu") {
                        Button("Start") { help() /*print("Start")*/ } // <-- *** 问题触发点 ***
                        Button("Resume") { print("Resume") }
                    }
                }
            }
            .navigationTitle("Scooby Doo")
        }
    }

    func help() { }
}

import CoreLocation
import Observation

@Observable
final class LocationManager: NSObject, CLLocationManagerDelegate {

    var lastLocation: CLLocation = CLLocation(latitude: 51.556000, longitude: -0.279511)

    let locationManager = CLLocationManager()

    init(dog: String = "") {
        super.init()

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = 2
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Ensure we have an actual location in the update.
        guard let location = locations.last else { return }

        lastLocation = location // Our published CLLocation.
    }
}

解决方案

原因分析

这是iOS 17 + Xcode 15 beta版本中SwiftUI的一个已知行为:当@Observable对象的属性更新触发视图刷新时,展开的Menu组件会因为视图重新渲染而被自动重置关闭。当按钮动作仅包含print时,SwiftUI会优化视图状态,不会标记视图需要完全刷新;但调用自定义方法时,会触发视图状态的更新标记,导致后续位置更新时视图完全重绘,进而关闭菜单。

修复方案:手动控制菜单展开状态

通过@State变量手动跟踪Menu的展开状态,避免视图刷新时自动关闭:

  1. 在ContentView中添加状态变量:
@State private var isMenuExpanded = false
  1. 修改Toolbar部分的Menu实现:
.toolbar {
    ToolbarItem(placement: .topBarTrailing) {
        // 使用isPresented绑定手动控制菜单状态
        Menu("Menu", isPresented: $isMenuExpanded) {
            Button("Start") {
                help()
                // 执行完操作后手动关闭菜单
                isMenuExpanded = false
            }
            Button("Resume") {
                print("Resume")
                isMenuExpanded = false
            }
        }
    }
}

额外优化建议

  1. 如果help()方法涉及异步操作,可将其放在Task中执行,避免阻塞UI线程导致意外状态变化。
  2. 适当增大locationManager.distanceFilter的值,减少不必要的位置更新频率,降低视图刷新次数。

内容的提问来源于stack exchange,提问作者Magnas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 07:54:54