如何在 Swift 3 中的 UIWebView 中显示没有基础 URL 的 PDF?
How to display a PDF without a base URL in a UIWebView in Swift 3?
我想在 UIWebView
. 中显示 PDF 文件我已经将其作为 Data
对象,所以我不需要 (并且不能)提供 baseURL
。
在Objective-C ...
...对应的方法定义如下:
- (void)loadData:(NSData *)data
MIMEType:(NSString *)MIMEType
textEncodingName:(NSString *)textEncodingName
baseURL:(NSURL *)baseURL;
所以我可以简单地将 nil
作为 baseURL
传递,如 Apple's Text Programming Guide.
中所述
在 Swift 2.0 ...
... baseURL
参数在 load(...)
函数中不是可选的(为什么?)所以我 不得不 传递一个有效的 NSURL
对象。幸运的是,另一个 Whosebug post 中描述了一个简单的解决方法:我只是创建了一个空的 NSURL
对象。
private func showPdf(data: NSData) {
webView.loadData(data,
MIMEType: "application/pdf",
textEncodingName: "utf-8",
baseURL: NSURL())
}
现在 Swift 3.0 ...
...方法签名已更改,baseURL
参数必须是 Swift URL
而不是 NSURL
:
open func load(_ data: Data,
mimeType MIMEType: String,
textEncodingName: String,
baseURL: URL)
这打破了解决方法,因为 URL
没有空的初始值设定项,并且不可能从空字符串创建 URL
,如 Swift 文档中所述:
/// Returns `nil` if a `URL` cannot be formed with the string
/// (for example, if the string contains characters that are illegal
/// in a URL, or is an empty string).
public init?(string: String)
所以问题是:
如何在 Swift 3 中的 UIWebView
内提供 baseURL
而加载 PDF(或任何其他 Web 内容)?
通常,如果您有数据,它是通过 URL 开始的,所以只需使用 URL。
或者我想 您可以使用应用程序包中任何内容的文件 URL 作为基础 URL。
或者您可以将 URL 构造为 NSURL 并使用 as
.
转换为 URL
或者将数据保存到磁盘并调用loadRequest
。
首先,马特的回答是正确的。似乎您几乎可以将任何 URL 用作 baseURL
,因为 webview 仅将其用于 HTML 文件中的内部链接,例如。如果您加载的是不包含任何内部链接的 PDF,则该参数将被忽略。您可以将 URL(string: "http://www.whosebug.com")!
作为 baseURL
传递,它仍然有效。我真的不明白为什么 Apple 没有首先将 baseURL
设为可选,但事实就是如此。
其次,我的UIWebView
没有加载PDF的原因与我问这个问题时所想的baseURL
无关。事实证明,我试图在 webview 中加载的 data
对象没有正确创建。
问题:
在 Swift 3 之前,可以像这样将数据写入上下文目标:
let mutableData = CFDataCreateMutable(nil, 0)
let dataConsumer = CGDataConsumerCreateWithCFData(mutableData)
let pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, nil)
if CGPDFDocumentGetNumberOfPages(document) > 0 {
CGPDFContextBeginPage(pdfContext, nil)
CGContextDrawPDFPage(pdfContext, page)
CGPDFContextEndPage(pdfContext)
}
此时 mutableData
对象已经写入并包含 PDF 页面数据。翻译成 new Swift 3 语法 如下:
let mutableData = CFDataCreateMutable(nil, 0)
let dataConsumer = CGDataConsumer(data: mutableData!)
let pdfContext = CGContext(consumer: dataConsumer!, mediaBox: &pageRect!, nil)
if (document?.numberOfPages)! > 0 {
pdfContext?.beginPDFPage(nil)
pdfContext?.drawPDFPage(page!)
pdfContext?.endPDFPage()
}
但是在 pdfContext
(或其等效 CGPDFContextEndPage()
)上调用 endPDFPage()
不再将任何数据写入目标。
解决方案:
你需要打电话
pdfContext?.closePDF()
这最终会将 PDF 数据写入您的上下文目标。
之后,您可以简单地按照我的问题中的描述在 webview 中加载 PDF 数据 - 无论您提供什么 baseURL
。
我想在 UIWebView
. 中显示 PDF 文件我已经将其作为 Data
对象,所以我不需要 (并且不能)提供 baseURL
。
在Objective-C ...
...对应的方法定义如下:
- (void)loadData:(NSData *)data
MIMEType:(NSString *)MIMEType
textEncodingName:(NSString *)textEncodingName
baseURL:(NSURL *)baseURL;
所以我可以简单地将 nil
作为 baseURL
传递,如 Apple's Text Programming Guide.
在 Swift 2.0 ...
... baseURL
参数在 load(...)
函数中不是可选的(为什么?)所以我 不得不 传递一个有效的 NSURL
对象。幸运的是,另一个 Whosebug post 中描述了一个简单的解决方法:我只是创建了一个空的 NSURL
对象。
private func showPdf(data: NSData) {
webView.loadData(data,
MIMEType: "application/pdf",
textEncodingName: "utf-8",
baseURL: NSURL())
}
现在 Swift 3.0 ...
...方法签名已更改,baseURL
参数必须是 Swift URL
而不是 NSURL
:
open func load(_ data: Data,
mimeType MIMEType: String,
textEncodingName: String,
baseURL: URL)
这打破了解决方法,因为 URL
没有空的初始值设定项,并且不可能从空字符串创建 URL
,如 Swift 文档中所述:
/// Returns `nil` if a `URL` cannot be formed with the string
/// (for example, if the string contains characters that are illegal
/// in a URL, or is an empty string).
public init?(string: String)
所以问题是:
如何在 Swift 3 中的 UIWebView
内提供 baseURL
而加载 PDF(或任何其他 Web 内容)?
通常,如果您有数据,它是通过 URL 开始的,所以只需使用 URL。
或者我想 您可以使用应用程序包中任何内容的文件 URL 作为基础 URL。
或者您可以将 URL 构造为 NSURL 并使用 as
.
或者将数据保存到磁盘并调用loadRequest
。
首先,马特的回答是正确的。似乎您几乎可以将任何 URL 用作 baseURL
,因为 webview 仅将其用于 HTML 文件中的内部链接,例如。如果您加载的是不包含任何内部链接的 PDF,则该参数将被忽略。您可以将 URL(string: "http://www.whosebug.com")!
作为 baseURL
传递,它仍然有效。我真的不明白为什么 Apple 没有首先将 baseURL
设为可选,但事实就是如此。
其次,我的UIWebView
没有加载PDF的原因与我问这个问题时所想的baseURL
无关。事实证明,我试图在 webview 中加载的 data
对象没有正确创建。
问题:
在 Swift 3 之前,可以像这样将数据写入上下文目标:
let mutableData = CFDataCreateMutable(nil, 0)
let dataConsumer = CGDataConsumerCreateWithCFData(mutableData)
let pdfContext = CGPDFContextCreate(dataConsumer, &pageRect, nil)
if CGPDFDocumentGetNumberOfPages(document) > 0 {
CGPDFContextBeginPage(pdfContext, nil)
CGContextDrawPDFPage(pdfContext, page)
CGPDFContextEndPage(pdfContext)
}
此时 mutableData
对象已经写入并包含 PDF 页面数据。翻译成 new Swift 3 语法 如下:
let mutableData = CFDataCreateMutable(nil, 0)
let dataConsumer = CGDataConsumer(data: mutableData!)
let pdfContext = CGContext(consumer: dataConsumer!, mediaBox: &pageRect!, nil)
if (document?.numberOfPages)! > 0 {
pdfContext?.beginPDFPage(nil)
pdfContext?.drawPDFPage(page!)
pdfContext?.endPDFPage()
}
但是在 pdfContext
(或其等效 CGPDFContextEndPage()
)上调用 endPDFPage()
不再将任何数据写入目标。
解决方案:
你需要打电话
pdfContext?.closePDF()
这最终会将 PDF 数据写入您的上下文目标。
之后,您可以简单地按照我的问题中的描述在 webview 中加载 PDF 数据 - 无论您提供什么 baseURL
。