You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI聊天应用异步TCP连接集成与异步读取优化咨询

解决方案

一、SwiftUI 集成方案

将 Client 类改造为 ObservableObject 类型的可观察对象,即可完美适配SwiftUI的状态管理机制:

  1. 改造Client类,新增@Published修饰的状态属性,用于通知UI更新,比如消息列表、连接状态、错误信息等。所有状态更新操作必须切回主队列执行,避免后台线程操作UI导致崩溃。
  2. 在App入口(@main修饰的App结构体)中初始化Client实例,通过.environmentObject()注入到整个视图树中,所有子视图都可以通过@EnvironmentObject直接获取Client实例,按钮点击等操作直接调用sendMessage、sendCommand方法即可。
  3. 移除原有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 17:06:02