Long Polling vs WebSocket 在 Swift 中的选择:2025 年 iOS 开发指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:iOS 开发者的永恒难题

\n

想象一下:您正在开发一个即时通讯应用或股票交易应用。用户期待实时通知,而您面临一个选择——Long Polling 还是 WebSocket?在 Swift 中,这两种方法都有其适用场景,但各有其细微差别。本文将不仅列举优缺点,还将深入分析真实的代码示例、性能表现、对电池的影响,并给出清晰的选择策略。让我们开始吧!

\n\n

Swift 中的 Long Polling 是什么?(为什么它不是“永久的请求”)

\n

Long Polling 是一种经典的 HTTP 请求,服务器不会立即关闭连接,而是保持打开状态,直到有新事件发生或超时。在 Swift 中,这可以通过 URLSession 配合自定义的 timeoutIntervalForRequest 来实现。

\n

许多人将 Long Polling 与普通的轮询(客户端每 5 秒请求一次服务器)混淆。区别在于,Long Polling 中服务器会在数据可用时主动“推送”数据,而客户端在收到响应后会立即发送新的请求。

\n\n

使用 async/await 的 Swift Long Polling 示例

\n
import Foundation\n\nclass LongPollingClient {\n    private let session: URLSession\n    private let baseURL = URL(string: "https://api.pythonlib.ru/events")!\n    private var isPolling = false\n    \n    init() {\n        let config = URLSessionConfiguration.default\n        config.timeoutIntervalForRequest = 60 // 长超时时间\n        config.waitsForConnectivity = true\n        self.session = URLSession(configuration: config)\n    }\n    \n    func startPolling() async {\n        isPolling = true\n        while isPolling {\n            do {\n                let (data, response) = try await session.data(from: baseURL)\n                guard let httpResponse = response as? HTTPURLResponse,\n                      httpResponse.statusCode == 200 else {\n                    continue\n                }\n                // 处理接收到的数据\n                if let events = try? JSONDecoder().decode([Event].self, from: data) {\n                    await handleEvents(events)\n                }\n            } catch {\n                // 如果超时,只需开始新的循环\n                if let urlError = error as? URLError, \n                   urlError.code == .timedOut {\n                    continue\n                }\n                // 其他错误——记录日志并等待\n                print("Polling error: \\(error.localizedDescription)")\n                try? await Task.sleep(nanoseconds: 5_000_000_000)\n            }\n        }\n    }\n    \n    func stopPolling() {\n        isPolling = false\n    }\n    \n    private func handleEvents(_ events: [Event]) async {\n        // 在主线程更新 UI\n        await MainActor.run {\n            NotificationCenter.default.post(name: .newEvents, object: events)\n        }\n    }\n}
\n

重要提示: 在出现错误时不要忘记使用 Task.sleep,以避免无限重连导致服务器过载。在 pythonlib.ru 上,我们测试了这种方案在 10k 客户端负载下的表现——服务器表现良好,但延迟会有所增加。

\n\n

Swift 中的 WebSocket:原生能力还是 Starscream?

\n

从 iOS 13 开始,Apple 通过 URLSessionWebSocketTask 提供了对 WebSocket 的原生支持。这意味着您可以不再依赖第三方库,尽管 Starscream 仍然是需要支持旧版 iOS(12 及以下)项目的热门选择。

\n\n

Swift 原生 WebSocket 示例(iOS 13+)

\n
import Foundation\n\nclass WebSocketManager: NSObject, URLSessionWebSocketDelegate {\n    private var webSocket: URLSessionWebSocketTask?\n    private let session: URLSession\n    \n    override init() {\n        let config = URLSessionConfiguration.default\n        config.timeoutIntervalForRequest = 60\n        self.session = URLSession(configuration: config)\n                

博客

书籍推荐