We keep getting intermittent app crash from our customers and it is related to initialisation of NSMutableAttributedString.
Code:
let result = try NSMutableAttributedString(data: data, options: htmlOptions, documentAttributes: nil) <- Crash here
The above code is executed in cellForRowAt inside a TableViewCell and in some code also in viewDidLoad of a view.
data only contains short html text or sometimes even empty string "".
We also cannot reproduce the issue when testing with simulator and our test devices.
If I google this issue, it seems like there is no official solution that really worked.
Suggestions to run in main thread or run in background and then post in main thread seems to contradict the description in the documentation about NSMutableAttributedString.
The HTML importer should not be called from a background thread (that is, the options dictionary includes NSDocumentTypeDocumentAttribute with a value of NSHTMLTextDocumentType). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.
Any recommendation on how to use NSMutableAttributedString properly without running into this crash?
Here is the crash logs:
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x1b3a9c518 __exceptionPreprocess
1 libobjc.A.dylib 0x1b2c779f8 objc_exception_throw
2 CoreFoundation 0x1b39b6148 +[_CFXNotificationTokenRegistration keyCallbacks]
3 Foundation 0x1b44c5f5c -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:]
4 UIKitCore 0x1e000d9b0 _prepareForCAFlush
5 UIKitCore 0x1e003a674 _beforeCACommitHandler
6 CoreFoundation 0x1b3a2d89c __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
7 CoreFoundation 0x1b3a285c4 __CFRunLoopDoObservers
8 CoreFoundation 0x1b3a28b40 __CFRunLoopRun
9 CoreFoundation 0x1b3a28354 CFRunLoopRunSpecific
10 UIFoundation 0x1be08fc78 -[NSHTMLReader _loadUsingWebKit]
11 UIFoundation 0x1be092bfc -[NSHTMLReader attributedString]
12 UIFoundation 0x1be0deb88 _NSReadAttributedStringFromURLOrData
13 UIFoundation 0x1be092b38 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:]
14 MyApp 0x10140b140 @nonobjc NSMutableAttributedString.init(data:options:documentAttributes:) (<compiler-generated>)
I really need the info that such a report contains
Someone else sent me an Apple crash report and that let me refresh my understanding of this issue. Sadly, this is a known bug in iOS (r. 23592459) that can potentially affect anyone who constructs an NSAttributedString
from HTML.
There isn’t a good workaround for this other than to avoid this API altogether. My advice:
-
If you’re displaying large chunks of complex HTML, use a
WKWebView
. -
If this HTML is highly constrained — perhaps you’re just using HTML as an easy way to transfer a constrained set of attributes, like bold and italics — create your own markup system that doesn’t relying on HTML. Or parse the HTML for just these attributes and use the result to create your attributed string.
-
Alternatively, consider using the Markdown support we added in macOS 12 and iOS 15. For the details, watch WWDC 2021 Session 10109 What’s new in Foundation.
IMPORTANT Foundation’s Markdown support is strongly integrated with SwiftUI but it’s not limited to SwiftUI, or even to Swift. It’s compatible with other UI frameworks and Objective-C.
I’m sorry I don’t have better news here.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"