NSAttributedString在将HTML转换为属性字符串时崩溃

15

我遇到一个状况,其中 try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) 会导致应用程序崩溃。

控制台上显示如下信息: Assertion failure in void _prepareForCAFlush(UIApplication *__strong)()

该函数被调用于一个 extension String 中。 当我在控制台上输入 'po' 值时:

(lldb) po self
<p>Obfuscated string\n</p>


(lldb) po data`
450 bytes
  count : 450
    pointer : 0x00007fd283d75630
    pointerValue : 140542131787312

(lldb) po NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
Obfuscated string
{
            NSColor = "kCGColorSpaceModelRGB 0 0 0 1 ";
            NSFont = "<UICTFont: 0x7fd283c47330> font-family: \"Helvetica\"; font-weight: normal; font-style: normal; font-size: 15.00pt";
            NSKern = 0;
            NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 15, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 19/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n), DefaultTabInterval 36, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0";
            NSStrokeColor = "kCGColorSpaceModelRGB 0 0 0 1 ";
            NSStrokeWidth = 0;
}

这个字符串存在于一个在UITableViewCell中显示的标签中。

当“键盘框架改变”时,函数会崩溃。iOS会重新绘制表格单元格,导致其内容被重新绘制。

由于崩溃发生在主线程上,因此该函数是在主线程上调用的。

可能导致此崩溃的原因是什么,我该如何解决?

编辑:表视图单元格代码

UITableViewDataSource 生成单元格:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellID = cellIdentifier(for: message)
        let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! MessageTableViewCell
        cell.message = message
        cell.setOutletValues()
        cell.selectionStyle = .none
        cell.delegate = self
        return cell

}

Cell的实现:

class MessageTableViewCell: UITableViewCell {

    var message: Message!

    // Message Body View
    @IBOutlet weak var messageBodyView: ZeroPaddingTextView!

    func setOutletValues() {
        setMessageBodyOutletValues()
    }

    internal func setMessageBodyOutletValues() {
        if let body = message.body {
            messageBodyView.attributedText = body.htmlToPlainAttributedString()
        }
    }
}

创建纯属性字符串的函数会对HTML进行一些样式上的添加(这是因为通过API传入的内容需要进行一些修改)。

func htmlToPlainAttributedString() -> NSAttributedString {
    let contentString = replacingOccurrences(of: "\n", with: "<br>")
    let styleSheet = "body {font-family: sans-serif; font-size: 15px; color: #000000;}\n a {text-decoration: none;}\n"
    let body = "<body>\(contentString)</body>"
    let html = "<html><head><style type=\"text/css\">\(styleSheet)</style></head>\(body)</html>"
    if let data = html.data(using: String.Encoding.unicode, allowLossyConversion: true) {
        do {
            return try NSAttributedString(data: data, options: [
                NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
        } catch {
            return NSAttributedString()
        }
    }
    return NSAttributedString()
}

控制台崩溃输出:

2017-09-05 22:37:14.692 trustedfamily-ios[70389:10080542] *** Assertion failure in void _prepareForCAFlush(UIApplication *__strong)(), /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.7.47/UIApplication.m:2395
2017-09-05 22:38:14.532 trustedfamily-ios[70389:10080542] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unexpected start state'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010452ab0b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00000001035e8141 objc_exception_throw + 48
    2   CoreFoundation                      0x000000010452ecf2 +[NSException raise:format:arguments:] + 98
    3   Foundation                          0x00000001031b769b -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 165
    4   UIKit                               0x0000000105a31575 _prepareForCAFlush + 499
    5   UIKit                               0x0000000105a6346b _beforeCACommitHandler + 15
    6   CoreFoundation                      0x00000001044d0717 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    7   CoreFoundation                      0x00000001044d0687 __CFRunLoopDoObservers + 391
    8   CoreFoundation                      0x00000001044b5038 CFRunLoopRunSpecific + 440
    9   UIFoundation                        0x000000010a103edc -[NSHTMLReader _loadUsingWebKit] + 1954
    10  UIFoundation                        0x000000010a10522a -[NSHTMLReader attributedString] + 22
    11  UIFoundation                        0x000000010a09ded6 _NSReadAttributedStringFromURLOrData + 8926
    12  UIFoundation                        0x000000010a09bb64 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 117
    13  trustedfamily-ios                   0x0000000101e9e6ad _TTOFE5UIKitCSo18NSAttributedStringcfzT4dataV10Foundation4Data7optionsGVs10DictionarySSP__18documentAttributesGSqGVs33AutoreleasingUnsafeMutablePointerGSqCSo12NSDictionary____S0_ + 173
    14  trustedfamily-ios                   0x0000000101e9d9d9 _TFE5UIKitCSo18NSAttributedStringCfzT4dataV10Foundation4Data7optionsGVs10DictionarySSP__18documentAttributesGSqGVs33AutoreleasingUnsafeMutablePointerGSqCSo12NSDictionary____S0_ + 89
    15  trustedfamily-ios                   0x0000000101e9d803 _TFE17trustedfamily_iosSS27htmlToPlainAttributedStringfT_CSo18NSAttributedString + 1459
    16  trustedfamily-ios                   0x00000001020152f9 _TFC17trustedfamily_ios20MessageTableViewCell26setMessageBodyOutletValuesfT_T_ + 601
    17  trustedfamily-ios                   0x0000000102013467 _TFC17trustedfamily_ios20MessageTableViewCell15setOutletValuesfT_T_ + 103
    18  trustedfamily-ios                   0x0000000101f9a22f _TFC17trustedfamily_ios32ConversationDetailViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 1199
    19  trustedfamily-ios                   0x0000000101f9a4d7 _TToFC17trustedfamily_ios32ConversationDetailViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 87
    20  UIKit                               0x0000000105ba4ab2 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 750
    21  UIKit                               0x0000000105ba4cf8 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
    22  UIKit                               0x0000000105b79639 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2845
    23  UIKit                               0x0000000105b774a4 -[UITableView _setNeedsVisibleCellsUpdate:withFrames:] + 201
    24  UIKit                               0x0000000105b9626a -[UITableView _rectChangedWithNewSize:oldSize:] + 1267
    25  UIKit                               0x0000000105b96a5c -[UITableView setBounds:] + 322
    26  UIKit                               0x0000000105adee73 -[UIView(Geometry) _applyISEngineLayoutValuesToBoundsOnly:] + 598
    27  UIKit                               0x0000000105adf15e -[UIView(Geometry) _resizeWithOldSuperviewSize:] + 125
    28  UIKit                               0x000000010648f0e9 -[UIScrollView(_UIOldConstraintBasedLayoutSupport) _resizeWithOldSuperviewSize:] + 46
    29  CoreFoundation                      0x00000001044bb652 __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke + 114
    30  CoreFoundation                      0x00000001044bb56f -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 335
    31  UIKit                               0x0000000105addbcc -[UIView(Geometry) resizeSubviewsWithOldSize:] + 183
    32  UIKit                               0x00000001063fa16d -[UIView(AdditionalLayoutSupport) _is_layout] + 168
    33  UIKit                               0x0000000105aea0a6 -[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 994
    34  UIKit                               0x0000000105afb55b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
    35  QuartzCore                          0x00000001057a4904 -[CALayer layoutSublayers] + 146
    36  QuartzCore                          0x0000000105798526 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 370
    37  UIKit                               0x0000000105ae9334 -[UIView(Hierarchy) layoutBelowIfNeeded] + 1108
    38  trustedfamily-ios                   0x0000000101fe3f4c _TFC17trustedfamily_ios32ConversationDetailViewController28changeBottomLayoutConstraintfT2toV12CoreGraphics7CGFloat_T_ + 284
    39  trustedfamily-ios                   0x0000000101fe3fac _TToFC17trustedfamily_ios32ConversationDetailViewController28changeBottomLayoutConstraintfT2toV12CoreGraphics7CGFloat_T_ + 44
    40  trustedfamily-ios                   0x0000000101fe3bf7 _TFFC17trustedfamily_ios32ConversationDetailViewController28changeBottomLayoutConstraintFT2toV12CoreGraphics7CGFloat8animatedSb8durationSd7optionsVSC22UIViewAnimationOptions_T_U_FT_T_ + 39
    41  trustedfamily-ios                   0x0000000101e572d7 _TTRXFo___XFdCb___ + 39
    42  UIKit                               0x0000000105af13da +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 572
    43  UIKit                               0x0000000105af18dd +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 99
    44  trustedfamily-ios                   0x0000000101fe3b7f _TFC17trustedfamily_ios32ConversationDetailViewController28changeBottomLayoutConstraintfT2toV12CoreGraphics7CGFloat8animatedSb8durationSd7optionsVSC22UIViewAnimationOptions_T_ + 943
    45  trustedfamily-ios                   0x0000000101fe3e1f _TToFC17trustedfamily_ios32ConversationDetailViewController28changeBottomLayoutConstraintfT2toV12CoreGraphics7CGFloat8animatedSb8durationSd7optionsVSC22UIViewAnimationOptions_T_ + 79
    46  trustedfamily-ios                   0x0000000101fe30e6 _TFC17trustedfamily_ios32ConversationDetailViewController23keyboardWillChangeFramefV10Foundation12NotificationT_ + 2278
    47  trustedfamily-ios                   0x0000000101fe3237 _TToFC17trustedfamily_ios32ConversationDetailViewController23keyboardWillChangeFramefV10Foundation12NotificationT_ + 71
    48  CoreFoundation                      0x00000001044c9c2c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    49  CoreFoundation                      0x00000001044c9b29 _CFXRegistrationPost + 425
    50  CoreFoundation                      0x00000001044c9892 ___CFXNotificationPost_block_invoke + 50
    51  CoreFoundation                      0x000000010448d102 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826
    52  CoreFoundation                      0x000000010448c261 _CFXNotificationPost + 673
    53  Foundation                          0x00000001030b6ca4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
    54  UIKit                               0x000000010649ce05 -[UIInputWindowController postStartNotifications:withInfo:] + 225
    55  UIKit                               0x000000010649f0af __77-[UIInputWindowController moveFromPlacement:toPlacement:starting:completion:]_block_invoke.871 + 381
    56  UIKit                               0x0000000105af13da +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 572
    57  UIKit                               0x0000000105af1853 +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:animations:start:completion:] + 116
    58  UIKit                               0x000000010649eacb -[UIInputWindowController moveFromPlacement:toPlacement:starting:completion:] + 1503
    59  UIKit                               0x00000001064a6d5e __43-[UIInputWindowController setInputViewSet:]_block_invoke.1318 + 97
    60  UIKit                               0x000000010649a59a -[UIInputWindowController performOperations:withTemplateNotificationInfo:] + 46
    61  UIKit                               0x00000001064a68ea -[UIInputWindowController setInputViewSet:] + 1753
    62  UIKit                               0x000000010649e14c -[UIInputWindowController performOperations:withAnimationStyle:] + 50
    63  UIKit                               0x0000000106114a8a -[UIPeripheralHost(UIKitInternal) setInputViews:animationStyle:] + 1505
    64  UIKit                               0x0000000106115c4b -[UIPeripheralHost(UIKitInternal) _preserveInputViewsWithId:animated:reset:] + 499
    65  UIKit                               0x0000000105bec35d -[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:] + 1145
    66  UIKit                               0x0000000105bedfae -[UIViewController _presentViewController:withAnimationController:completion:] + 4660
    67  CoreFoundation                      0x00000001044b2c6c __invoking___ + 140
    68  CoreFoundation                      0x00000001044b2b40 -[NSInvocation invoke] + 320
    69  UIKit                               0x0000000105bd1633 -[_UIDelayedPresentationContext finishDelayedPresentation:] + 230
    70  UIKit                               0x0000000105be9416 -[UIViewController _endDelayingPresentation] + 93
    71  CoreFoundation                      0x00000001044b2c6c __invoking___ + 140
    72  CoreFoundation                      0x00000001044b2b40 -[NSInvocation invoke] + 320
    73  FrontBoardServices                  0x000000010a1f25f6 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    74  FrontBoardServices                  0x000000010a1f246d -[FBSSerialQueue _performNext] + 186
    75  FrontBoardServices                  0x000000010a1cb360 -[FBSWorkspace synchronizeSystemAnimationFencesWithCleanUpBlock:] + 1549
    76  UIKit                               0x0000000105a311d4 -[UIApplication _synchronizeSystemAnimationFencesWithSpinCleanUpBlock:] + 543
    77  UIKit                               0x0000000105ab22cd __realPreCommitHandler_block_invoke + 395
    78  QuartzCore                          0x000000010575532c _ZNK2CA11Transaction5Fence13run_callbacksEv + 40
    79  QuartzCore                          0x0000000105727f7c _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 528
    80  QuartzCore                          0x0000000105754130 _ZN2CA11Transaction6commitEv + 468
    81  QuartzCore                          0x0000000105754b37 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 115
    82  CoreFoundation                      0x00000001044d0717 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    83  CoreFoundation                      0x00000001044d0687 __CFRunLoopDoObservers + 391
    84  CoreFoundation                      0x00000001044b5720 __CFRunLoopRun + 1200
    85  CoreFoundation                      0x00000001044b5016 CFRunLoopRunSpecific + 406
    86  GraphicsServices                    0x000000010a9eda24 GSEventRunModal + 62
    87  UIKit                               0x0000000105a38134 UIApplicationMain + 159
    88  trustedfamily-ios                   0x0000000101ff6837 main + 55
    89  libdyld.dylib                       0x000000010894465d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

2
请将表格视图单元格的代码发布。 - Suhit Patil
@suhit,我添加了更多的代码,请查看我的编辑。 - Bocaxica
2
你能发布一下崩溃日志的跟踪信息吗? - Charles Srstka
我曾经遇到过类似的问题,当我在ViewController的视图中使用TableView时。我将reloadData()函数调用移动到viewDidAppear()中,从而允许HTML转换为字符串在主线程中进行。这解决了我的问题。希望它也能帮到你。 - Ayazmon
1
我在类似的问题上已经给出了答案。https://dev59.com/rOk6XIcBkEYKwwoYBvTb#52751998 或许可以帮到你。 - Huy.Vu
显示剩余8条评论
2个回答

4

尝试将您的 HTML 转换为 NSAttributedString 内部

DispatchQueue.main.async {

}


谢谢,这个问题在我的项目中不再出现了,所以我不记得我是如何解决或绕过它的。但我很确定它都在主线程上运行。 - Bocaxica
@Bocaxica 我也是这么认为的。 - IBAction

1
我在现场看到了一个非常类似的崩溃情况,但我自己无法重现它。
让我们尝试这个方法,看看是否有帮助:
guard UIApplication.shared.applicationState == .active else { return NSAttributedString() }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接