React Native调用Swift时URLSession.dataTask进度监听失效问题
问题解决:React Native调用Swift代码时task.progress.observe不触发
核心原因
你遇到的问题本质是观察者对象的生命周期被提前回收:
- 在Playground中,局部变量的生命周期会被运行机制延长,所以
observation能一直存在直到任务完成; - 但在React Native的Native模块函数里,
observation是局部变量,函数执行完毕后就会被ARC自动释放,导致进度观察失效,无法触发回调。
解决方案
把observation从局部变量改为Native模块类的实例变量,让它的生命周期和模块实例绑定,避免被提前回收。
修改后的代码示例
import React class YourRNModule: NSObject, RCTBridgeModule { // 定义实例变量保存进度观察者,避免被ARC提前释放 private var downloadProgressObservation: NSKeyValueObservation? static func moduleName() -> String! { return "YourRNModule" // 替换成你的实际模块名 } static func requiresMainQueueSetup() -> Bool { return true } @objc(downloadFileFromGoogleDrive:authHeader:savedEncryptedFileUri:withResolver:withRejecter:) func downloadFileFromGoogleDrive(uri: String, authHeader: String, savedEncryptedFileUri: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { guard let url = URL(string: uri) else { reject("Invalid URL", nil, nil) return } var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "GET" urlRequest.setValue(authHeader, forHTTPHeaderField: "Authorization") let task = URLSession.shared.dataTask(with: urlRequest) {data, response, error in // 任务完成后移除观察者,释放资源 self.downloadProgressObservation = nil if let error = error { reject("request failed", error.localizedDescription, error) return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { reject("download failed", String(describing: response), nil) return } guard let data = data else { reject("no data received", nil, nil) return } let url = URL(fileURLWithPath: savedEncryptedFileUri) do { try data.write(to: url) resolve(true) } catch { reject("cannot load data", error.localizedDescription, error) } } // 将观察者赋值给实例变量,延长生命周期 self.downloadProgressObservation = task.progress.observe(\.fractionCompleted) { progress, _ in print("下载进度:\(progress.fractionCompleted)") // 如果需要向React Native实时传递进度,可以使用RCTEventEmitter发送事件 } task.resume() } }
额外注意事项
- 如果需要同时处理多个下载任务,不要用单个实例变量保存观察者,建议用
[URLSessionDataTask: NSKeyValueObservation]这样的字典分别存储每个任务的观察者,避免互相覆盖; - 任务完成(成功/失败)后,记得将观察者置为
nil,及时释放资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Kim Mỹ
相关产品推荐
相关产品推荐

