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

Swift中如何通过WebSocket实时更新UITableView指定行数据

解决WebSocket推送更新UITableView指定行的问题

我看了你的代码,目前存在两个核心问题:一是收到WebSocket数据后没有更新数据源数组arrContacts,导致列表一直没有数据;二是直接调用reloadData()会刷新整个列表,不仅效率低,还可能丢失单元格状态。下面是针对性的解决方案,我们一步步来调整:

核心思路

  1. 精准更新数据源:收到推送数据时,先判断对应股票是否已在arrContacts中——存在则更新属性,不存在则添加新数据。这里用instid作为唯一标识(匹配你订阅的SBIN标的)。
  2. 局部刷新UI:找到对应数据在数组中的索引,生成IndexPath,只刷新该行而非整个列表,提升性能。

修改后的完整代码

import UIKit
import Starscream

struct Stocks: Codable {
    let changepercent: String
    let changeprice: String
    let close: String
    let currentprice: String
    let high: String
    let id: Int
    let low: String
    let name: String
    let `open`: String
    let type: String
    let instid: String
    let exchange: String
}

class ViewController: UIViewController, WebSocketDelegate, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet weak var stocktableView: UITableView!
    var arrContacts = [Stocks]()
    var socket: WebSocket!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 确保TableView代理和数据源绑定(Storyboard未设置时手动添加)
        stocktableView.delegate = self
        stocktableView.dataSource = self
        
        var request = URLRequest(url: URL(string: "ws://192.168.18.97:8080/sss/landingstream")!)
        request.timeoutInterval = 5
        socket = WebSocket(request: request)
        socket.delegate = self
        socket.connect()
    }
    
    // MARK: Websocket Delegate Methods.
    func websocketDidConnect(socket: WebSocketClient) {
        print("websocket is connected")
    }
    
    func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
        if let e = error as? WSError {
            print("websocket is disconnected: \(e.message)")
        } else if let e = error {
            print("websocket is disconnected: \(e.localizedDescription)")
        } else {
            print("websocket disconnected")
        }
    }
    
    func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
        print("Received text: \(text)")
        let decoder = JSONDecoder()
        do {
            let newStockData = try decoder.decode(Stocks.self, from: text.data(using: .utf8)!)
            
            // 主线程更新数据源和UI(WebSocket回调默认在后台线程)
            DispatchQueue.main.async {
                // 查找是否已有该标的数据
                if let existingIndex = self.arrContacts.firstIndex(where: { $0.instid == newStockData.instid }) {
                    // 更新现有数据
                    self.arrContacts[existingIndex] = newStockData
                    // 生成对应行的IndexPath
                    let targetIndexPath = IndexPath(row: existingIndex, section: 0)
                    // 仅刷新指定行
                    self.stocktableView.reloadRows(at: [targetIndexPath], with: .automatic)
                } else {
                    // 新标的数据,添加到数组并插入对应行
                    self.arrContacts.append(newStockData)
                    let newIndexPath = IndexPath(row: self.arrContacts.count - 1, section: 0)
                    self.stocktableView.insertRows(at: [newIndexPath], with: .automatic)
                }
            }
        } catch {
            print("数据解析出错: \(error)")
        }
    }
    
    func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
        print("Received data: \(data.count)")
    }
    
    // MARK: Write Text Action
    @IBAction func writeText(_ sender: UIBarButtonItem) {
        socket.write(string: "{\"requestType\": \"INSTRUMENT_PRICE\",\"topic\": \"SBIN\"}")
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arrContacts.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "StocksCell", for: indexPath)
        let stock = arrContacts[indexPath.row]
        // 优化单元格显示内容,展示更丰富的股票信息
        cell.textLabel?.text = "\(stock.name) 当前价: \(stock.currentprice)"
        cell.detailTextLabel?.text = "涨跌幅: \(stock.changepercent) | 涨跌额: \(stock.changeprice)"
        return cell
    }
    
    // MARK: Disconnect Action
    @IBAction func disconnect(_ sender: UIBarButtonItem) {
        if socket.isConnected {
            sender.title = "Connect"
            socket.disconnect()
        } else {
            sender.title = "Disconnect"
            socket.connect()
        }
    }
}

关键改动说明

  • 数据源精准更新:通过firstIndex(where:)定位已有数据的位置,避免重复添加,保证数据一致性。
  • UI局部刷新:用reloadRows(at:with:)替代reloadData(),只更新变化的行,避免不必要的渲染,提升列表性能,同时保留单元格的滚动、选中状态。
  • 线程安全:所有数据源修改和UI操作都包裹在DispatchQueue.main.async中,符合iOS主线程更新UI的要求。
  • 单元格内容优化:扩展了单元格显示的信息,让数据展示更直观。

这样,每两秒收到WebSocket推送时,你的UITableView就会精准更新对应行的数值啦。

内容的提问来源于stack exchange,提问作者Ben10

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:37:58