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

Apple TV从Parse服务器下载PDF的存储与显示异常问题求助

Apple TV端从Parse服务器加载并展示PDF的问题

问题背景

  • 已搭建Parse服务器,存储425KB的小型PDF文件,需在Apple TV端展示
  • PDF更新频繁,必须从Parse服务器获取,不能随应用打包放入主包

遇到的问题

  • Apple TV不存在NSDocumentsDirectory,使用NSCachesDirectory缓存目录时,代码仅半数时间生效:
    • 在AppDelegate启动时执行,PDF可能未就绪,无法正常展示
    • 按需执行则存在加载延迟,有时甚至完全无法显示
  • 尝试使用NSTemporaryDirectory()同样无效:模拟器运行正常,但Apple TV端需要执行两次代码才能完成PDF下载并渲染

现有代码

-(void)sermonTime {
    //Check if PFFile exists, if so, display PDF, if not, blank time.
    if ([self.entry[@"SermonPresIncluded"] isEqualToString:@"NO"]) {
        [self blankTime];
    }
    else {
        NSLog(@"SermonTime");
        PFFileObject *thumbnail = self.entry[@"SermonPDF"];
       
        [thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
            NSString *documentsDirectory = [paths objectAtIndex:0];
            NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:[self.entry valueForKey:@"DateOfService"]] stringByAppendingString:@".pdf"];
            
            [imageData writeToFile:pdfPath atomically:YES];
            
            
            NSURL *url = [NSURL fileURLWithPath:pdfPath];
            self.view.backgroundColor = [UIColor blackColor];
            self.arrayOfVerses = @[@"allverses"];
            CGPDFDocumentRef pdfDocument = [self openPDF:url];
            [self drawDocument:pdfDocument];

        }];
    }
      
}

解决方案

1. 修复缓存逻辑,增加错误处理与写入校验

当前代码缺失下载错误处理、文件写入结果检查,且未确保UI操作在主线程执行,这是TV端不稳定的核心原因。修改后台下载块逻辑:

[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    // 处理下载错误
    if (error) {
        NSLog(@"PDF下载失败: %@", error.localizedDescription);
        [self blankTime];
        return;
    }
    if (!imageData || imageData.length == 0) {
        NSLog(@"下载的PDF数据为空");
        [self blankTime];
        return;
    }

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cacheDir = [paths firstObject];
    NSString *pdfFileName = [[self.entry valueForKey:@"DateOfService"] stringByAppendingString:@".pdf"];
    NSString *pdfPath = [cacheDir stringByAppendingPathComponent:pdfFileName];
    
    // 删除旧缓存避免冲突
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:pdfPath]) {
        [fm removeItemAtPath:pdfPath error:nil];
    }
    
    // 校验文件写入结果
    BOOL writeSuccess = [imageData writeToFile:pdfPath atomically:YES];
    if (!writeSuccess) {
        NSLog(@"PDF文件写入失败");
        [self blankTime];
        return;
    }

    // 确保UI操作在主线程执行
    dispatch_async(dispatch_get_main_queue(), ^{
        NSURL *url = [NSURL fileURLWithPath:pdfPath];
        self.view.backgroundColor = [UIColor blackColor];
        self.arrayOfVerses = @[@"allverses"];
        CGPDFDocumentRef pdfDocument = [self openPDF:url];
        if (pdfDocument) {
            [self drawDocument:pdfDocument];
            CGPDFDocumentRelease(pdfDocument); // 释放资源避免内存泄漏
        } else {
            NSLog(@"无法打开PDF文件");
            [self blankTime];
        }
    });
}];

2. 优化加载时机

  • 不要在AppDelegate启动时直接调用sermonTime,改为在视图控制器的viewDidAppear:中执行,此时视图已准备就绪,能保证渲染逻辑正常运行
  • 若需预加载,可在viewDidLoad:中启动下载,但渲染逻辑必须等下载完成后在主线程执行,或延迟到viewDidAppear:触发

3. 增加缓存校验,避免重复下载

每次加载前先检查缓存目录是否存在对应PDF,还可通过Parse文件的大小或更新时间校验缓存是否过期:

// 先检查缓存有效性
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDir = [paths firstObject];
NSString *pdfFileName = [[self.entry valueForKey:@"DateOfService"] stringByAppendingString:@".pdf"];
NSString *pdfPath = [cacheDir stringByAppendingPathComponent:pdfFileName];

NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:pdfPath]) {
    // 校验文件大小是否匹配服务器文件
    NSNumber *remoteFileSize = self.entry[@"SermonPDF"][@"size"];
    if (remoteFileSize) {
        NSDictionary *fileAttr = [fm attributesOfItemAtPath:pdfPath error:nil];
        if ([fileAttr fileSize] == remoteFileSize.integerValue) {
            // 缓存有效,直接渲染
            dispatch_async(dispatch_get_main_queue(), ^{
                NSURL *url = [NSURL fileURLWithPath:pdfPath];
                self.view.backgroundColor = [UIColor blackColor];
                self.arrayOfVerses = @[@"allverses"];
                CGPDFDocumentRef pdfDocument = [self openPDF:url];
                if (pdfDocument) {
                    [self drawDocument:pdfDocument];
                    CGPDFDocumentRelease(pdfDocument);
                } else {
                    [self blankTime];
                }
            });
            return;
        }
    }
}

// 缓存无效,执行下载逻辑
PFFileObject *thumbnail = self.entry[@"SermonPDF"];
[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
    // 上面的下载处理逻辑
}];

4. 关于临时目录的说明

Apple TV的NSTemporaryDirectory()会被系统定期清理,且文件写入后存在磁盘同步延迟,不适合存储需要稳定访问的PDF,优先使用NSCachesDirectory即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:15:43