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

ODR使用异常:中断下载后beginAccessingResources无法二次完成

解决ODR下载中断后beginAccessingResources无响应的问题

这个ODR的坑我之前踩过!当下载被后台中断(比如按Home键)后,系统的资源请求状态很容易卡住,导致后续调用beginAccessingResources永远得不到回调,磁盘状态一直显示Downloading其实是因为之前的请求没有被正确清理。

问题根源

当NSBundleResourceRequest的下载进程被后台中断时,系统并没有自动重置该请求的状态,它会一直处于NSBundleResourceRequestStateDownloading状态,但实际下载已经停止。此时再次调用beginAccessingResources,系统会认为已有一个活跃的下载请求,不会触发新的回调逻辑。

解决方案

1. 主动管理请求生命周期,后台时取消活跃请求

在应用进入后台时,主动取消当前的资源请求,并清理引用,避免状态残留:

// 声明成员变量持有当前请求
@property (nonatomic, strong) NSBundleResourceRequest *currentResourceRequest;

// 应用进入后台的回调(在AppDelegate或SceneDelegate中)
- (void)applicationDidEnterBackground:(UIApplication *)application {
    if (self.currentResourceRequest) {
        // 取消当前请求
        [self.currentResourceRequest cancel];
        // 清理引用
        self.currentResourceRequest = nil;
    }
}

2. 监听下载进度,处理停滞情况

如果请求在前台也出现进度停滞的情况,可以通过KVO监听progress属性,当长时间无进度更新时,主动取消并重新发起请求:

- (void)startResourceRequestWithTag:(NSString *)tag {
    self.currentResourceRequest = [[NSBundleResourceRequest alloc] initWithTags:@[tag]];
    
    [self.currentResourceRequest conditionallyBeginAccessingResourcesWithCompletionHandler:^(BOOL resourcesAvailable) {
        if (resourcesAvailable) {
            NSLog(@"<!> Resource is available.");
            self.currentResourceRequest = nil;
        } else {
            NSLog(@"<!> Resource is NOT available.");
            
            // 添加进度监听
            [self.currentResourceRequest.progress addObserver:self 
                                                  forKeyPath:@"fractionCompleted" 
                                                     options:NSKeyValueObservingOptionNew 
                                                     context:nil];
            
            [self.currentResourceRequest beginAccessingResourcesWithCompletionHandler:^(NSError * __nullable error) {
                // 移除监听
                [self.currentResourceRequest.progress removeObserver:self forKeyPath:@"fractionCompleted"];
                
                if (error) {
                    NSLog(@"Download failed: %@", error.localizedDescription);
                    self.currentResourceRequest = nil;
                    // 可选:重新发起请求
                    [self startResourceRequestWithTag:tag];
                } else {
                    NSLog(@"Download completed!");
                    self.currentResourceRequest = nil;
                }
            }];
        }
    }];
}

// KVO回调处理进度停滞
- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                       context:(void *)context {
    if ([keyPath isEqualToString:@"fractionCompleted"]) {
        NSProgress *progress = (NSProgress *)object;
        static NSTimeInterval lastUpdateTime;
        static double lastProgressValue;
        NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
        
        // 检查5秒内是否无进度更新
        if (currentTime - lastUpdateTime > 5 && progress.fractionCompleted == lastProgressValue) {
            // 进度停滞,取消请求并重新发起
            [self.currentResourceRequest cancel];
            [self.currentResourceRequest.progress removeObserver:self forKeyPath:@"fractionCompleted"];
            self.currentResourceRequest = nil;
            [self startResourceRequestWithTag:yourTag]; // 替换为你的资源标签
        }
        
        lastUpdateTime = currentTime;
        lastProgressValue = progress.fractionCompleted;
    }
}

3. 检查请求状态,重置卡住的请求

在发起新请求前,检查是否有遗留的活跃请求,如果有则先取消:

- (void)prepareResourceRequest {
    // 如果存在未完成的请求,先取消
    if (self.currentResourceRequest && self.currentResourceRequest.state == NSBundleResourceRequestStateDownloading) {
        [self.currentResourceRequest cancel];
        self.currentResourceRequest = nil;
    }
    // 发起新请求
    [self startResourceRequestWithTag:yourTag];
}

总结

核心思路是避免请求状态残留,通过主动管理请求的生命周期(后台取消、停滞时重置),确保每次发起的beginAccessingResources都是基于一个全新的、状态干净的NSBundleResourceRequest实例,这样就能解决中断后无响应的问题。

内容的提问来源于stack exchange,提问作者Simon Lam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:46:21