Swift中.onReceive未按预期工作:加载界面无法正常关闭
问题分析与解决方案
核心问题
- 类型声明错误:
Variables类中AllAirplanes的类型String<Array>是无效语法,正确的字符串数组类型应为[String],错误类型导致@Published无法正常发送更新通知。 - 数组更新方式错误:更新
AllAirplanes时使用removeAll()+append()的原地修改方式,@Published仅在属性被重新赋值时触发更新,原地修改数组不会改变其引用地址,因此无法触发视图刷新。
修正步骤
1. 修复Variables类的类型声明
class Variables: ObservableObject { @Published var AllAirplanes: [String] = [] // 修正为正确的字符串数组类型 }
2. 修改Firebase数据获取逻辑,通过赋值新数组触发更新
@StateObject var v = Variables() func getAllAirplanes() { db.collection("Airplanes") .addSnapshotListener { querySnapshot, error in guard let documents = querySnapshot?.documents else { print("Error fetching documents: \(error!)") return } // 用临时数组存储数据,避免原地修改原数组 var tempAirplanes: [String] = [] for document in documents { print("\(document.documentID) => \(document.data())") tempAirplanes.append(document.documentID) } // 移除指定元素 tempAirplanes.removeAll { $0 == "Simulator" } // 直接赋值新数组,触发@Published的更新通知 v.AllAirplanes = tempAirplanes print( """ ------------------------------ All Airplanes: \(v.AllAirplanes) ------------------------------ """ ) } }
3. 优化视图加载逻辑
修复@Published后,视图会自动响应数组变化,推荐使用.onChange替代.onReceive,逻辑更直观:
@EnvironmentObject var v: Variables @State private var isActiveView = false @State private var isAnimation = false var body: some View { if !isActiveView { VStack { // 加载界面内容,比如加载动画或提示文本 Text("加载中...") } .onAppear { // 视图出现时触发数据获取 getAllAirplanes() } .onChange(of: v.AllAirplanes) { newAirplanes in // 数组非空时执行跳转逻辑 guard !newAirplanes.isEmpty else { return } DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { withAnimation(Animation.easeOut(duration: 1.0)) { isAnimation.toggle() } } DispatchQueue.main.asyncAfter(deadline: .now() + 3.8) { withAnimation { isActiveView.toggle() locationViewModel.getUserLocation() } } } } else { // 主界面内容 MainView() } }
补充说明
原代码中.onReceive仅触发一次,是因为类型错误导致@Published无法正常工作,加上原地修改数组不触发更新通知,视图无法感知数组内容变化。修复类型和更新方式后,@Published会在数组变化时正确通知视图,.onChange就能正常响应所有数组更新。
内容的提问来源于stack exchange,提问作者user17864647
相关产品推荐
相关产品推荐

