尝试从子视图修改@EnvironmentObject失败:对象为只读属性
问题分析与解决方案
你遇到的错误Cannot assign to property: 'currentPosition' is a get-only property有两个核心原因:
1. @EnvironmentObject是只读的,不能直接替换实例
@EnvironmentObject这个属性包装器的设计是让你读取共享的ObservableObject实例,而不是直接给它赋值一个新的实例。它的wrappedValue是只读的,所以你不能写currentPosition = CurrentPosition(...)这种代码。
2. Coordinator不能使用@EnvironmentObject
你的Coordinator是NSObject的子类,并不是SwiftUI View,所以@EnvironmentObject属性包装器在它里面是无效的——SwiftUI不会自动给非View的类注入环境对象,这个属性实际上不会被正确初始化。
正确的解决方案
我们需要做两个关键修改:
第一步:给Coordinator传递CurrentPosition实例
在MapView的makeCoordinator()方法里,把当前的currentPosition实例传递给Coordinator,让它持有引用:
第二步:直接更新CurrentPosition的已发布属性
不需要创建新的CurrentPosition实例,直接修改现有实例的northEast和southWest属性——因为它们被@Published标记,属性变化会自动通知所有订阅的视图。
修改后的完整MapView代码如下:
struct MapView: UIViewRepresentable { @Binding var weatherStations: [WeatherStation] @Binding var selectedWeatherStation: WeatherStation? @EnvironmentObject var currentPosition: CurrentPosition final class Coordinator: NSObject, MKMapViewDelegate { // 持有CurrentPosition的引用 private let currentPosition: CurrentPosition // 通过初始化传入实例 init(currentPosition: CurrentPosition) { self.currentPosition = currentPosition } func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) { // 直接更新已发布属性,而非替换整个实例 currentPosition.northEast = mapView.northEastCoordinate currentPosition.southWest = mapView.southWestCoordinate } } // 创建Coordinator时传入currentPosition func makeCoordinator() -> Coordinator { Coordinator(currentPosition: currentPosition) } // 实现makeUIView和updateUIView(你的原有逻辑保留) func makeUIView(context: Context) -> MKMapView { let mapView = MKMapView() mapView.delegate = context.coordinator // 其他地图初始化设置... return mapView } func updateUIView(_ uiView: MKMapView, context: Context) { // 地图更新逻辑... } }
为什么这样能解决问题?
- 你的
CurrentPosition是ObservableObject,带有@Published属性,修改这些属性会自动触发所有依赖它的视图更新,完全满足你"移动地图时更新坐标,用于API请求"的需求。 - 通过初始化传递的方式给Coordinator提供
CurrentPosition实例,避开了非View类无法使用@EnvironmentObject的问题,让Coordinator能正确修改共享状态。
内容的提问来源于stack exchange,提问作者trusk
相关产品推荐
相关产品推荐

