html - 尝试将 HTML 转换为属性字符串,但遇到运行时崩溃或长期警告
问题描述
目标:将传入的 HMTL 翻译成 AttributedString。
两者都通过 UIViewRepresentable 视图:
两种方法:
- 通过 UITextView;或者
- 通过 WebKit。
#1:通过 UIView
我最初选择这条路线是为了避免 Webkit 的麻烦。这是代码:
import SwiftUI
struct VaccineDetailView: View {
@State var htmlText = htmlString
@State var text = htmlString
var body: some View {
TextView(htmlText: $text)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
// =====================================================================================================
struct TextView: UIViewRepresentable {
@Binding var htmlText: String
func makeUIView(context: Context) -> UITextView {
UITextView()
}
func updateUIView(_ uiView: UITextView, context: Context) {
let htmlData = NSString(string: htmlText).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html]
do {
let attributedString = try NSAttributedString(data: htmlData!, options: options, documentAttributes: nil)
uiView.attributedText = attributedString
} catch {
print("Unexpected error: \(error).")
}
}
}
但是,当我在模拟器中关闭并重新打开应用程序时遇到了以下运行时错误:
这是控制台消息的一部分:
...[plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600001c81300> F8BB1C28-BAE8-11D6-9C31-00039315CD46
=== AttributeGraph: cycle detected through attribute 93896 ===
=== AttributeGraph: cycle detected through attribute 93432 ===
=== AttributeGraph: cycle detected through attribute 93432 ===
*** Assertion failure in void _UIApplicationDrainManagedAutoreleasePool()(), UIApplication+AutoreleasePool.m:171
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unexpected start state'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff2041faf6 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2041f91f +[NSException raise:format:] + 0
3 Foundation 0x00007fff2076d633 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 166
...
...
2) 通过 WebKit:
我没有使用 WebKit 导致运行时崩溃:
import SwiftUI
import WebKit
struct VaccineDetailView: View {
@State var htmlText = htmlString
@State var text = htmlString
var body: some View {
TextView(htmlText: $text)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
// =====================================================================================================
struct TextView: UIViewRepresentable {
@Binding var htmlText: String
func makeUIView(context: Context) -> UITextView {
UITextView()
}
// Converting HTML to String:
func updateUIView(_ uiView: UITextView, context: Context) {
NSAttributedString.loadFromHTML(string: htmlString) { attr, _, _ in
uiView.attributedText = attr
}
}
}
但是我确实得到以下信息:
Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
Could not signal service com.apple.WebKit.Networking: 113: Could not find specified service
选项 #2 似乎是更安全的方法,但我必须处理 WebKit 可以找到指定服务的 *repeated* 警告。
注意:我只是使用 WebKit 来翻译 HTML。我在这里没有使用 URLSession(通过在其他地方发布/订阅接受)。这可能是问题所在……WebKit 不理解“不需要服务”。
我不明白为什么选项 #1 会崩溃。
问题:
- 为什么选项 #1 在重新打开应用程序时总是崩溃?
- 我如何告诉 WebKit 不要担心任何“指定服务”?
2a)我可以将其合并到与 URLSession.publisher 关联的订阅者语法中...以避免警告吗?如何?
这是翻译后的输出:
解决方案
我仅在 ios14 中遇到与 TTTAttributeLabel 相同的崩溃。事实证明 DispatchQueue.main.async 解决了崩溃。
struct TextView: UIViewRepresentable {
@Binding var htmlText: String
func makeUIView(context: Context) -> UITextView {
UITextView()
}
func updateUIView(_ uiView: UITextView, context: Context) {
let htmlData = NSString(string: htmlText).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html]
do {
DispatchQueue.main.async {
let attributedString = try NSAttributedString(data: htmlData!, options: options, documentAttributes: nil)
uiView.attributedText = attributedString
}
} catch {
print("Unexpected error: \(error).")
}
}
}
推荐阅读
- html - 如何开始使用 flex?
- docker - 将节点加入集群后看不到节点 - “getsockopt:连接被拒绝”
- invisible-recaptcha - 无形的recaptcha大幅增加了首次交互时间
- r - tryCatch inside dplyr's mutate?
- r - 从列中提取数据并将提取填充为现有数据框中的新变量
- c# - how to map one to many optional recursive relationship in Entity Framework core
- amazon-web-services - 处理 SQS 消息的最佳方式
- makefile - 编译 Python3.6 给出致命错误:zlib.h: No such file or directory
- ios - Swift 4 表格视图出现错误的单元格
- python - Google Cloud Dataflow table query returns more data than table has