SwiftUI聊天应用异步TCP连接集成与异步读取优化咨询
解决方案
一、SwiftUI 集成方案
将 Client 类改造为 ObservableObject 类型的可观察对象,即可完美适配SwiftUI的状态管理机制:
- 改造
Client类,新增@Published修饰的状态属性,用于通知UI更新,比如消息列表、连接状态、错误信息等。所有状态更新操作必须切回主队列执行,避免后台线程操作UI导致崩溃。 - 在App入口(
@main修饰的App结构体)中初始化Client实例,通过.environmentObject()注入到整个视图树中,所有子视图都可以通过@EnvironmentObject直接获取Client实例,按钮点击等操作直接调用sendMessage、sendCommand方法即可。 - 移除原有
Client中didStopCallback里的exit调用,不要直接终止App进程,改为更新连接状态属性,由UI层给用户展示重连提示即可。
改造后的Client核心示例:
import Foundation import Network import SwiftUI class Client: ObservableObject { let connection: Connection let host: NWEndpoint.Host let port: NWEndpoint.Port let queue: DispatchQueue = DispatchQueue.init(label: "keepAlive") // 通知UI更新的状态属性 @Published var messages: [Frame.MessageWrapper] = [] @Published var isConnected: Bool = false @Published var errorMsg: String? init(host: String, port: UInt16) { self.host = NWEndpoint.Host(host) self.port = NWEndpoint.Port(rawValue: port)! let nwConnection = NWConnection(host: self.host, port: self.port, using: .tcp) connection = Connection(nwConnection: nwConnection) // 绑定连接回调 connection.didReceiveMessage = { [weak self] msg in DispatchQueue.main.async { self?.messages.append(msg) } } connection.didChangeConnectionState = { [weak self] isConnected, error in DispatchQueue.main.async { self?.isConnected = isConnected self?.errorMsg = error?.localizedDescription } } } // 原有start、stop、send相关方法保留即可 }
注入示例:
@main struct ChatApp: App { @StateObject private var client = Client(host: "你的服务器地址", port: 端口号) var body: some Scene { WindowGroup { ContentView() .environmentObject(client) } } }
视图中使用示例:
struct ChatView: View { @EnvironmentObject var client: Client @State private var inputText: String = "" let currentChannel: UUID = // 你的频道ID var body: some View { List(client.messages) { msg in Text(msg.value) } HStack { TextField("输入消息", text: $inputText) Button("发送") { client.sendMessage(content: inputText, channel: currentChannel) inputText = "" } .disabled(!client.isConnected) } } }
二、替换递归读取的异步实现
iOS 15及以上版本可以直接使用NWConnection原生的Async/Await API替代递归读取,代码更简洁,逻辑更清晰:
// Connection类中替换原来的setupReceive方法 func start() { print("connection will start") nwConnection.stateUpdateHandler = stateDidChange(to:) nwConnection.start(queue: queue) running = true // 开启异步任务循环接收数据 Task { do { while running { let (data, _) = try await nwConnection.receive(minimumIncompleteLength: 1, maximumLength: maxReadLength) guard !data.isEmpty else { continue } guard let message = String(data: data, encoding: .utf8) else { continue } switch(Frame.parse(reader: BufferedString(str: message))) { case .success(let res): if let msg = res as? Frame.MessageWrapper { // 回调给Client层 didReceiveMessage?(msg) } else if let cmd = res as? Frame.Cmd { // 处理指令 } case .failure(let err): print(err) } } } catch { connectionDidFail(error: error) } } // KeepAlive也可以用Task实现,不需要管理RunLoop Task { while running { try? await Task.sleep(nanoseconds: UInt64(KeepAlive) * 1_000_000_000) guard running else { break } send(data: Data(Frame.KeepAlive().serialize())) } } }
内容的提问来源于stack exchange,提问作者hyxos
相关产品推荐
相关产品推荐

