SwiftUI,不能从委托回调中更改状态? (附代码)
Posted
技术标签:
【中文标题】SwiftUI,不能从委托回调中更改状态? (附代码)【英文标题】:SwiftUI, can't change state from within delegate callback? (code attached) 【发布时间】:2021-09-14 11:28:22 【问题描述】:任何人都能发现为什么当我在“updateUIView”回调中设置“firstPass”状态变量时它没有设置状态?作为输出我看到:
First Pass1: true
First Pass2: true. // <= not set to false as expected
我也没有在 Xcode 中设置这个状态“firstPass = false”,这里有一个 Xcode 警告:“在视图更新期间修改状态,这将导致未定义的行为。”
import SwiftUI
import MapKit
struct GCMapView
@State var firstPass : Bool = true
func makeCoordinator() -> Coordinator
return Coordinator(self)
class Coordinator: NSObject, MKMapViewDelegate
var parent: GCMapView
init(_ parent: GCMapView)
self.parent = parent
super.init()
extension GCMapView : UIViewRepresentable
func makeUIView(context: Context) -> MKMapView
let map = MKMapView()
map.delegate = context.coordinator
map.showsUserLocation = true
return map
func updateUIView(_ view: MKMapView, context: Context)
print("--- updateUIView ---")
if firstPass
print("First Pass1: ", firstPass)
firstPass = false. // <<=== *** THIS DOES NOT WORK ****
print("First Pass2: ", firstPass)
else
print("Subsequent Passes")
【问题讨论】:
我很惊讶你能编译这个。删除firstPass = false.
之后的点UIViewRepresentable从extension GCMapView
移动到struct GCMapView
【参考方案1】:
此操作导致循环,因为它使 SwiftUI 视图无效,从而导致调用 updateUIView
等等,因此 SwiftUI 渲染引擎将其丢弃(自动修复)。
不太确定您是否需要这样的if
,但可能的解决方案是在下一个事件循环中单独更新,例如
if firstPass
print("First Pass1: ", firstPass)
DispatchQueue.main.async
firstPass = false
print("First Pass2: ", firstPass)
else
使用 Xcode 13 / ios 15 测试
【讨论】:
非常感谢 - 所以我猜这是处理这个问题的唯一方法吗?我想在第一次通过时在地图上设置一个新的视点(矩形和中心位置),然后再不移动它,以便用户可以滚动。我必须在 SwiftUI 中使用协调器模式方法,因此 updateUIView 回调在这里为委托提供。因此,您认为似乎没有其他方法可以更新@State 吗?您似乎需要为“struct GCMapView”使用结构(而不是类),所以想不出另一种方法,而是在此处的结构中使用 @State 变量以上是关于SwiftUI,不能从委托回调中更改状态? (附代码)的主要内容,如果未能解决你的问题,请参考以下文章
将数据从委托 Swift 类传递到 SwiftUI 结构中的 EnvironmentObject
SwiftUI如何从视图调用或通知scenedelegate