我正在使用此代码段
var htmlToAttributedString: NSAttributedString? {
guard let data = data(using: .utf8) else { return NSAttributedString() }
do {
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil) // Get crash on this line
} catch let error {
print(error.localizedDescription)
return NSAttributedString()
}
}
var htmlToString: String {
return htmlToAttributedString?.string ?? ""
}
在HTML
显示UITableViewCell
文本
cell.textViewMessage.attributedText = msg.htmlToAttributedString
启动第一次没有崩溃,但在那之后,当我运行代码时崩溃并且之后没有工作。
线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x10)
#Edit HTML要在单元格中显示的字符串
<p>Here\'s a short video tour. Press play to start.</p><br><iframe class=\"ql-video\" frameborder=\"0\" allowfullscreen=\"true\" src=\"https://www.youtube.com\"></iframe><br>
#Edit 1 - 我试图在Playground中运行此代码并且它正常工作,除非它现在显示错误。请参阅附图
看起来问题是标记,而不是每个标记都可以在uitextview中显示。您可以在uiwebview中更好地显示这些标记
我认为问题是iframe标签。
要显示iFrame,请使用uiwebview或wkwebview。
谢谢
这是一个受this repo启发的解决方案。基本上我们删除iframe
标签,并用可点击的img
替换它:
let msg = "<p>Here\'s a short video tour. Press play to start.</p><br><iframe class=\"ql-video\" frameborder=\"0\" allowfullscreen=\"true\" src=\"https://www.youtube.com/embed/wJcOvdkI7mU\"></iframe><br>"
//Let's get the video id
let range = NSRange(location: 0, length: msg.utf16.count)
let regex = try! NSRegularExpression(pattern: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)")
guard let match = regex.firstMatch(in: msg, options: [], range: range) else {
fatalError("Couldn't find the video ID")
}
let videoId: String = String(msg[Range(match.range, in: msg)!])
//Let's replace the the opening iframe tag
let regex2 = try! NSRegularExpression(pattern:
"<[\\s]*iframe[\\s]+.*src=")
let str2 = regex2.stringByReplacingMatches(in: msg, options: [], range: range, withTemplate: "<a href=")
//And then replace the closing tag
let regex3 = try! NSRegularExpression(pattern:
"><\\/iframe>")
let range2 = NSRange(location: 0, length: str2.utf16.count)
let str3 = regex3.stringByReplacingMatches(in: str2, options: [], range: range2, withTemplate: "><img src=\"https://img.youtube.com/vi/" + videoId + "/0.jpg\" alt=\"\" width=\"\(textView.frame.width)\" /></a>") // You could adjust the width and height to your liking
//Set the text of the textView
textView.attributedText = str3.htmlToAttributedString
textView.delegate = self
要在用户点按并按住图像时打开Youtube应用,请实现此委托方法:
extension NameOfYourViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
UIApplication.shared.open(URL, options: [:])
return true
}
}
如果未安装youtube应用,则视频将在Safari中播放。
结果如下:
将您的选项更改为:
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue
]
试试这个UITextView:
let string = "<h2>The bedding was hardly able to cover it.</h2>"
if !string.isEmpty{
if let htmlData = string.data(using:String.Encoding.unicode) {
do {
let attributedText = try NSAttributedString(data: htmlData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
cell.textViewMessage.attributedText = attributedText
} catch let e as NSError {
print("Couldn't translate \(string): \(e.localizedDescription) ")
}
}
尝试使用UILabel将html文本设置为带有html标签的uilabel:
extension String {
var withoutHtmlTags: String {
let a = self.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
return a.replacingOccurrences(of: "&[^;]+;", with: "", options: String.CompareOptions.regularExpression, range: nil)
}
}
let string = "<h2>The bedding was hardly able to cover it.</h2>"
textUIlabel.text = string.withoutHtmlTags
这个问题的原因是表视图,这个错误将非常随机地发生并且难以重现,因为它更具体到设备内存和UI绘制过程,这可能导致在后台线程中执行该方法。在重新分配和释放表格单元格时,在某些地方,表格单元格可能会在后台线程上调用此方法,而HTML导入程序使用非线程安全的WebKit导入程序并期望位于主线程上。
如何重现此错误:使用UITest运行代码并且它会更频繁地崩溃,因为单元测试会显着减慢UI绘制过程
解决方案:解码HTML到String应该在主线程上,但是在主线程的模型层中执行此操作,而不是在创建单元格时执行此操作。这将使UI更加流畅。
为什么没有在catch块中捕获崩溃:您的应用程序因为未处理的语言异常而崩溃,正如Objective-C的异常处理基础结构所使用的那样。 SWIFT就像Cocoa的NSError一个很好的包装器。 Swift无法处理Objective-C异常,因此框架中的Objective-C代码的异常不会由Swift错误处理程序引起。