Swift中如何通过WebSocket实时更新UITableView指定行数据
解决WebSocket推送更新UITableView指定行的问题
我看了你的代码,目前存在两个核心问题:一是收到WebSocket数据后没有更新数据源数组arrContacts,导致列表一直没有数据;二是直接调用reloadData()会刷新整个列表,不仅效率低,还可能丢失单元格状态。下面是针对性的解决方案,我们一步步来调整:
核心思路
- 精准更新数据源:收到推送数据时,先判断对应股票是否已在
arrContacts中——存在则更新属性,不存在则添加新数据。这里用instid作为唯一标识(匹配你订阅的SBIN标的)。 - 局部刷新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
相关产品推荐
相关产品推荐

