使用GCD时@ObservedObject变更后SwiftUI View未更新问题求助
问题根因
@Published对值类型的触发条件是整个属性值发生替换,你当前修改的是nmea结构体内部mtw元组的子属性,属于对结构体的原地修改,不会触发@Published的更新通知,视图自然不会刷新。- 你当前是把所有文件内容一次性读取后集中处理,即使修复了通知触发问题,也只会看到最终一行数据的结果,看不到逐行更新的效果。
修复方案
1. 触发@Published更新通知
修改parseNMEA方法,先复制原有nmea结构体修改完成后,再整体赋值给nmea属性,触发值替换逻辑:
private func parseNMEA(fields: [String]){ switch fields[0].slice(3, 5){ case "MTW": // 先复制原有结构体,修改副本 var updatedNMEA = nmea updatedNMEA.mtw.src = fields[0].slice(1, 2) updatedNMEA.mtw.timeStamp = Date() updatedNMEA.mtw.temp = Double(fields[1]) ?? 0 updatedNMEA.mtw.units = "º" + fields[2] // 整体赋值,触发@Published通知 nmea = updatedNMEA print("MTW: \(nmea.mtw)") default: print("Missing sentence: \(fields[0].slice(1, 2))") return } }
2. 实现逐行更新效果
如果需要看到每一行数据处理后的视图更新,修改receiveNMEA方法,逐行调度到主线程处理,可增加短延迟方便观察过程:
private func receiveNMEA() { do { let path = Bundle.main.path(forResource: "reprex-input", ofType: "txt") ?? "" let message = try String(contentsOfFile: path, encoding: .utf8) // 拆分所有非空行 let allLines = message.components(separatedBy: .newlines).filter { !$0.isEmpty } // 逐行延迟处理,间隔0.3秒方便观察更新效果 for (lineIndex, line) in allLines.enumerated() { DispatchQueue.main.asyncAfter(deadline: .now() + Double(lineIndex) * 0.3) { self.handleSingleLine(line: line) } } } catch { print("Error:", error) } } // 新增单条数据处理方法 private func handleSingleLine(line: String) { var fields = line.components(separatedBy: ",") guard let lastField = fields.last else { return } let splitLast = lastField.components(separatedBy: "*") fields.removeLast() fields.append(contentsOf: splitLast) guard fields.count >= 2 else { return } let valid = checksum(message: line, checksum: fields.last ?? "") if valid { parseNMEA(fields: fields) } }
适配TCP实时流场景
如果是TCP持续接收数据流的场景,不需要加延迟,每次收到一条完整的NMEA报文后,直接在主线程调用handleSingleLine处理即可,每收到一条有效数据视图就会自动刷新一次。
内容的提问来源于stack exchange,提问作者MarkCX
相关产品推荐
相关产品推荐

