Objective-C 为 PDF 创建映射文件
Objective-C create mapped file for PDF
我正在创建一个这样的文件:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
}
_previewItemURL = [NSURL fileURLWithPath:filePath];
我在 UIDocumentInteractionController 中显示它,如下所示:
if (_previewItemURL) {
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:_previewItemURL];
documentInteractionController.delegate = self;
[documentInteractionController presentPreviewAnimated:YES];
}
但是,有时我保存的 PDF 文件太大,有时 5.5MB,这导致 UIDocumentInteractionController 需要一些时间来加载 PDF。我正在阅读这里 ,建议创建一个 'mapped' 文件。我的问题是我不明白如何创建一个。这两天我一直在谷歌搜索,我就是不明白。
我认为问题出在 PDF 上,因为我试过这个:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pgnPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.pdf", @"example"]];
//filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
//if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *newFile = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"pdf"];
[[NSFileManager defaultManager] copyItemAtPath:newFile toPath:pgnPath error:&error];
//[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
//}
//_previewItemURL = [[NSBundle mainBundle] URLForResource:@"example" withExtension:@"pdf"];
_previewItemURL = [NSURL fileURLWithPath:pgnPath];
对于 5.5MB 的 PDF,一切似乎都很好,问题可能出在我获取 PDF 的方式上吗?我正在从 Web 服务获取字节,这是我的调用:
task = [dataSource.areaData GetPDFFileTestTwo:[NSString stringWithFormat:@"%@",encodedUrlStr] completion:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
NSData *dataBytes;
for (NSDictionary *dict in tableArray) {
NSString *base64 = dict[@"data"];
dataBytes = [[NSData alloc] initWithBase64EncodedString:base64 options:0];
}
if (dataBytes) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
}
_previewItemURL = [NSURL fileURLWithPath:filePath];
if (_previewItemURL) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:_previewItemURL];
documentInteractionController.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
[documentInteractionController presentPreviewAnimated:YES];
});
});
}
}
}];
这里是 GetPDFFileTestTwo
-(NSURLSessionDataTask *)GetPDFFileTestTwo:(NSString *)PDFFile completion:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler{
NSString *FileBrowserRequestString = [NSString stringWithFormat:@"%@?PDFFile=%@",kIP,PDFFile];
NSURL *JSONURL = [NSURL URLWithString:FileBrowserRequestString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if(completionHandler)
{
completionHandler(data, response, error);
}
}];
[dataTask resume];
return dataTask;
}
kIP 是一个字符串,也就是网络服务 URL
您的问题;
- create a 'mapped' file. My question is I don't understand how to
create one.
因此,让我指出 UIDocumentInteractionController 没有接受 NSData 的输入,因此您将无法创建内存映射文件来使用它。我还检查了 header 是否有任何其他线索,但没有找到任何线索。
https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller
在寻找解决方案时,我看到 QLPreviewController 提到了 'data',但我发现它也不接受 NSData。
https://developer.apple.com/documentation/quicklook/qlpreviewcontroller
我最终选择了 WebKit 中的 WKWebView,它确实支持使用 NSData,即内存映射,并且可以非常快速地加载我制作的包含图片和文本的 15 MB PDF。
我用大 PDF 创建了一个项目并试用了它,效果很好。请随时检查它。
https://github.com/eSpecialized/PDFDocViewerMapped
'mapped' 的工作原理;
任何可以使用 NSData 的东西都可以使用映射文件,除非它一次需要整个数据集。具有单个图像的 PDF 与多页 PDF 是无法映射和可以映射的很好的例子。
NSError *errors;
NSData *docFileData = [NSData dataWithContentsOfFile:docFileWithPath options:NSDataReadingMappedAlways error:&errors];
映射 NSData 的选项;
https://developer.apple.com/documentation/foundation/nsdatareadingoptions?language=objc
NSDataReadingMappedIfSafe // Hint to map the file in if possible and safe
NSDataReadingMappedAlways // Hint to map the file in if possible. This takes precedence over NSDataReadingMappedIfSafe if both are given.
- could the issue be with how I getting the PDF?
远程获取 PDF 意味着您必须下载文档。
想想你在做什么,获取 Pdf,将其保存在本地,然后在采用 URL 而不是 NSData 的 UIDocument Interaction 控制器中打开它。
希望这符合您的解决方案标准;
UIDocumentInteractionController 限制需要 URL 的
WKWebView - 允许使用可内存映射的 NSData。
查看 PDF 的第 3 方选项 - 任何可以接受 NSData 的都是
使用的候选者。寻找 CocoaPods 并在 GitHub 上寻找 PDF,iOS PDF,
等等
您不是 "creating" 映射文件。您正在将其读入映射到文件中字节的 NSData
。这意味着,in-memory NSData
字节在下面映射到文件中的字节。
这是一种读取映射文件的方法:
https://github.com/atomicbird/atomictools/blob/master/NSData%2BreallyMapped.h
如果不能将 NSData
传递给控制器进行预览,映射就没有意义。即使可以,您也必须确保控制器在使用前不会复制您的数据。
考虑使用PDFKit
框架,你可以用NSData
初始化PDFDocument
并在PDFView
中显示它。
我正在创建一个这样的文件:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
}
_previewItemURL = [NSURL fileURLWithPath:filePath];
我在 UIDocumentInteractionController 中显示它,如下所示:
if (_previewItemURL) {
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:_previewItemURL];
documentInteractionController.delegate = self;
[documentInteractionController presentPreviewAnimated:YES];
}
但是,有时我保存的 PDF 文件太大,有时 5.5MB,这导致 UIDocumentInteractionController 需要一些时间来加载 PDF。我正在阅读这里 ,建议创建一个 'mapped' 文件。我的问题是我不明白如何创建一个。这两天我一直在谷歌搜索,我就是不明白。
我认为问题出在 PDF 上,因为我试过这个:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pgnPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.pdf", @"example"]];
//filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
//if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *newFile = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"pdf"];
[[NSFileManager defaultManager] copyItemAtPath:newFile toPath:pgnPath error:&error];
//[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
//}
//_previewItemURL = [[NSBundle mainBundle] URLForResource:@"example" withExtension:@"pdf"];
_previewItemURL = [NSURL fileURLWithPath:pgnPath];
对于 5.5MB 的 PDF,一切似乎都很好,问题可能出在我获取 PDF 的方式上吗?我正在从 Web 服务获取字节,这是我的调用:
task = [dataSource.areaData GetPDFFileTestTwo:[NSString stringWithFormat:@"%@",encodedUrlStr] completion:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
NSData *dataBytes;
for (NSDictionary *dict in tableArray) {
NSString *base64 = dict[@"data"];
dataBytes = [[NSData alloc] initWithBase64EncodedString:base64 options:0];
}
if (dataBytes) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,PDFFile];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:dataBytes attributes:nil];
}
_previewItemURL = [NSURL fileURLWithPath:filePath];
if (_previewItemURL) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:_previewItemURL];
documentInteractionController.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
[documentInteractionController presentPreviewAnimated:YES];
});
});
}
}
}];
这里是 GetPDFFileTestTwo
-(NSURLSessionDataTask *)GetPDFFileTestTwo:(NSString *)PDFFile completion:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler{
NSString *FileBrowserRequestString = [NSString stringWithFormat:@"%@?PDFFile=%@",kIP,PDFFile];
NSURL *JSONURL = [NSURL URLWithString:FileBrowserRequestString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if(completionHandler)
{
completionHandler(data, response, error);
}
}];
[dataTask resume];
return dataTask;
}
kIP 是一个字符串,也就是网络服务 URL
您的问题;
- create a 'mapped' file. My question is I don't understand how to create one.
因此,让我指出 UIDocumentInteractionController 没有接受 NSData 的输入,因此您将无法创建内存映射文件来使用它。我还检查了 header 是否有任何其他线索,但没有找到任何线索。 https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller
在寻找解决方案时,我看到 QLPreviewController 提到了 'data',但我发现它也不接受 NSData。 https://developer.apple.com/documentation/quicklook/qlpreviewcontroller
我最终选择了 WebKit 中的 WKWebView,它确实支持使用 NSData,即内存映射,并且可以非常快速地加载我制作的包含图片和文本的 15 MB PDF。
我用大 PDF 创建了一个项目并试用了它,效果很好。请随时检查它。 https://github.com/eSpecialized/PDFDocViewerMapped
'mapped' 的工作原理;
任何可以使用 NSData 的东西都可以使用映射文件,除非它一次需要整个数据集。具有单个图像的 PDF 与多页 PDF 是无法映射和可以映射的很好的例子。
NSError *errors;
NSData *docFileData = [NSData dataWithContentsOfFile:docFileWithPath options:NSDataReadingMappedAlways error:&errors];
映射 NSData 的选项;
https://developer.apple.com/documentation/foundation/nsdatareadingoptions?language=objc
NSDataReadingMappedIfSafe // Hint to map the file in if possible and safe
NSDataReadingMappedAlways // Hint to map the file in if possible. This takes precedence over NSDataReadingMappedIfSafe if both are given.
- could the issue be with how I getting the PDF?
远程获取 PDF 意味着您必须下载文档。 想想你在做什么,获取 Pdf,将其保存在本地,然后在采用 URL 而不是 NSData 的 UIDocument Interaction 控制器中打开它。
希望这符合您的解决方案标准;
UIDocumentInteractionController 限制需要 URL 的
WKWebView - 允许使用可内存映射的 NSData。
查看 PDF 的第 3 方选项 - 任何可以接受 NSData 的都是 使用的候选者。寻找 CocoaPods 并在 GitHub 上寻找 PDF,iOS PDF, 等等
您不是 "creating" 映射文件。您正在将其读入映射到文件中字节的 NSData
。这意味着,in-memory NSData
字节在下面映射到文件中的字节。
这是一种读取映射文件的方法:
https://github.com/atomicbird/atomictools/blob/master/NSData%2BreallyMapped.h
如果不能将 NSData
传递给控制器进行预览,映射就没有意义。即使可以,您也必须确保控制器在使用前不会复制您的数据。
考虑使用PDFKit
框架,你可以用NSData
初始化PDFDocument
并在PDFView
中显示它。