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
相关产品推荐
相关产品推荐

