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

Posted

技术标签:

【中文标题】将 HTML 转换为属性字符串时 NSAttributedString 崩溃【英文标题】:NSAttributedString crash when converting HTML to Attrubuted String 【发布时间】:2018-02-13 20:11:00 【问题描述】:

我遇到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


单元的实现:

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

【问题讨论】:

也发布 tableviewcell 代码 @suhit 我添加了更多代码,请查看我的编辑。 您能否发布崩溃日志中的跟踪信息? @Bocaxica“键盘框架变化”你的意思是设备旋转? 我已经对类似的问题做出了回答。 https://***.com/a/52751998/2794052也许能帮上忙。 【参考方案1】:

尝试让你的html在NSAttributedString里面进行转换

DispatchQueue.main.async

【讨论】:

谢谢,这个问题不再出现在我的项目中,所以我不记得我是如何解决或解决它的。我很确定这一切都在主线程上运行。 @Bocaxica 我也这么认为【参考方案2】:

我在现场看到这种崩溃的情况非常相似,但我自己无法重现。

让我们试试这个,看看是否有帮助:

guard UIApplication.shared.applicationState == .active else  return NSAttributedString() 

【讨论】:

以上是关于将 HTML 转换为属性字符串时 NSAttributedString 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

如何将html属性代码转换为字符串

使用对象解构赋值时,为啥将属性“名称”转换为字符串? [复制]

如何将自定义属性转换为 Json 字符串

Swift NSAttributedString 修剪

将 HTML 表格(作为字符串)转换为 JS 对象数组

将属性文本转换为 UTF8 字符串?