Attempting to translate HTML into an Attributed String but ran into either a runtime crash or chronic warnings

Viewed 419

Goal: To translate incoming HMTL into AttributedString.
Both via a UIViewRepresentable View: Two Ways To Do This:

  1. Via a UITextView; or
  2. Via WebKit.

#1: via UIView
I initially chose this route to avoid the hassles of Webkit. Here's the code:

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).")

        }
    }
}

However I ran into the following runtime error when I closed & re-opened the app within the simulator:

enter image description here

Here's part of the console message:

...[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) Via WebKit:
I don't get the runtime crash using 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
        }
    }
}

However I do get the following:

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

Option #2 appears to be the safer approach but I have to deal with the *repeated* warning that WebKit could to find the specified service.
Note: I'm merely using WebKit to translate HTML. I'm not using URLSession here (accept via publish/subscribe elsewhere). This may be the problem...WebKit doesn't understand about 'no need for service'.

I don't understand why Option #1 would crash.

Questions:

  1. Why does Option #1 always crash upon reopen app?
  2. How do I tell WebKit not to worry about any 'specified service'?
    2a)Can I incorporate this into the subscriber syntax associated with the URLSession.publisher...to avoid the warnings? How?

Here's the translated output:

enter image description here

1 Answers

I experience same crash with TTTAttributeLabel ONLY in ios14. It turns out a DispatchQueue.main.async resolves the crash.

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).")

        }
    }
}
Related