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

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ỹ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:22:45