URLSession代理方法失效,如何分段读取API大文件并按需终止?
解决URLSession分段读取文件并提前终止的问题
嘿,我懂这种卡着不动的难受——1.6MB的文件说大不大,但硬等全加载完确实没必要,而且代理方法还不听话,太闹心了😅
先揪出你大概率踩的坑:默认的URLSession.shared是不会触发代理方法的!你必须手动创建一个带代理的会话,并且要持有它的强引用,不然会话被提前释放,代理回调根本跑不起来。
我给你整理了一套能正常工作的代码,每一步都标了注释,你可以对照着改:
class ViewController: UIViewController, URLSessionDataDelegate { // 必须强引用自定义的URLSession,不然会被提前释放 private var urlSession: URLSession! // 用来累积接收到的数据片段 private var receivedData = Data() // 替换成你要找的目标数据(比如特定字符串、标记位) private let targetMarker = "我要找的关键内容".data(using: .utf8)! override func viewDidLoad() { super.viewDidLoad() // 1. 创建自定义Session配置,指定代理为当前ViewController let sessionConfig = URLSessionConfiguration.default urlSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue.main) // 2. 创建数据任务并启动 guard let apiUrl = URL(string: "你的API地址") else { print("URL格式错误") return } let dataTask = urlSession.dataTask(with: apiUrl) dataTask.resume() } // MARK: - URLSessionDataDelegate 核心回调 // 每次收到服务器发来的数据片段时都会调用这个方法 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { // 把新数据加到累积容器里 receivedData.append(data) // 检查当前累积的数据里是否包含目标内容 if receivedData.contains(targetMarker) { print("找到目标数据了!立即停止接收") // 主动取消任务,终止后续数据传输 dataTask.cancel() // 这里处理你拿到的有效数据,比如解析成字符串或JSON processTargetData(receivedData) } // 可选:打印当前已接收大小,方便调试 print("已接收:\(receivedData.count) bytes") } // 任务完成(包括正常结束、主动取消、出错)时触发 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if let error = error { // 主动取消的错误不用当成异常处理 if (error as NSError).code == NSURLErrorCancelled { print("任务已主动终止") } else { print("任务出错:\(error.localizedDescription)") } } else { print("任务正常完成,但未找到目标数据") } // 重置数据容器,避免下次请求被污染 receivedData.removeAll() } // 自定义方法:处理找到的目标数据 private func processTargetData(_ data: Data) { if let content = String(data: data, encoding: .utf8) { print("解析到的内容:\(content)") // 这里写你的业务逻辑,比如提取关键信息、更新UI等 } } // 页面销毁时销毁Session,避免内存泄漏 deinit { urlSession.invalidateAndCancel() } }
你之前可能踩的几个关键坑:
- 没持有自定义Session:如果你的
urlSession是局部变量或者用了weak修饰,会话会在任务启动后被释放,代理方法根本不会触发,必须用强引用。 - 误用URLSession.shared:这个共享会话只支持闭包形式的请求,没法中途终止数据接收,必须自定义带代理的会话。
- 代理方法签名错误:比如方法名拼写错、参数类型不对,系统就不会调用它,最好用Xcode的自动补全生成代理方法。
- 没主动取消任务:找到目标数据后一定要调用
dataTask.cancel(),不然服务器还会继续发数据,你还是得等完全接收完。
按照这个代码改,应该就能实现“分段接收,找到数据就停”的需求了。
内容的提问来源于stack exchange,提问作者user9413278
相关产品推荐
相关产品推荐

