SIGABRT when using NSAttributedString.DocumentType.html

I have been battling with a problem that is completely and utterly perplexing to me. Swift 4, High Sierra 10.13.6, Xcode 9.4.1 (9F2000).


I have a view-based NSTable. In each cell is an NSTextField which I am trying to populate with arbitrary HTML for formatting. In effect it is a "chat view" for a Matrix client I am working on.


The Apple documentation suggests I can just give it some HTML and it will convert into an attributed string, so I have effectively done that by extending

String
and adding
func toAttributedStringFromHTML(justify: NSTextAlignment) -> NSAttributedString:


guard let data = data(using: .utf16, allowLossyConversion: true) else { return NSAttributedString() }
let str: NSMutableAttributedString = try NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)


This is called from the table cell setup:


    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    ...
               cellAttributedStringValue = (event.content["formatted_body"] as! String).trimmingCharacters(in: .whitespacesAndNewlines).toAttributedStringFromHTML(justify: .left)


This often works fine, but occasionally it crashes with a SIGABRT. The stack trace points to an NSInternalInconsistencyException but Xcode points to the

let str: NSMutableAttributedString = try NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
line.


The stack trace is exceptionally long, but looks like this:


2018-08-08 22:31:54.168731+0100 Seaglass[67287:21638720] *** Assertion failure in -[NSTableRowData insertRowsAtIndexes:withRowAnimation:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1561.60.100/TableView.subproj/NSTableRowData.m:7470
2018-08-08 22:31:54.173683+0100 Seaglass[67287:21638720] [General] An uncaught exception was raised
2018-08-08 22:31:54.173718+0100 Seaglass[67287:21638720] [General] insertRowsAtIndexes:withRowAnimation: can not happen while updating visible rows!
2018-08-08 22:31:54.173849+0100 Seaglass[67287:21638720] [General] (
  0   CoreFoundation                      0x00007fff389102db __exceptionPreprocess + 171
  1   libobjc.A.dylib                     0x00007fff5fab1c76 objc_exception_throw + 48
  2   CoreFoundation                      0x00007fff38916072 +[NSException raise:format:arguments:] + 98
  3   Foundation                          0x00007fff3aa3f340 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
  4   AppKit                              0x00007fff35f22273 -[NSTableRowData insertRowsAtIndexes:withRowAnimation:] + 304
  5   AppKit                              0x00007fff35f21ffa -[NSTableView _doUpdatedWorkWithHandler:] + 106
  6   AppKit                              0x00007fff35f21e72 -[NSTableView insertRowsAtIndexes:withAnimation:] + 162
  7   AppKit                              0x00007fff3611209d -[NSTableView noteNumberOfRowsChanged] + 198
  8   Seaglass                            0x00000001000121ba _T08Seaglass22MainViewRoomControllerC09matrixDidD7MessageySo7MXEventC5event_14SwiftMatrixSDK19MXTimelineDirectionO9directionSo11MXRoomStateC04roomR0tFTf4gddn_n + 2714
  9   Seaglass                            0x000000010000bf72 _T08Seaglass22MainViewRoomControllerCAA06MatrixD8DelegateA2aDP09matrixDidD7MessageySo7MXEventC5event_05SwiftF3SDK19MXTimelineDirectionO9directionSo11MXRoomStateC04roomS0tFTW + 18
  10  Seaglass                            0x0000000100024208 _T08Seaglass14MatrixServicesC15subscribeToRoomySS6roomId_tFySo7MXEventC_05SwiftB3SDK19MXTimelineDirectionOSo11MXRoomStateCtcfU_Tf4gngnn_n + 4360
  11  Seaglass                            0x0000000100022612 _T08Seaglass14MatrixServicesC15subscribeToRoomySS6roomId_tFySo7MXEventC_05SwiftB3SDK19MXTimelineDirectionOSo11MXRoomStateCtcfU_TA + 34
  12  SwiftMatrixSDK                      0x0000000100d183cc _T0So15MXEventTimelineC14SwiftMatrixSDKE14listenToEventsypSayAC0A4TypeOGSg_ySo0A0C_AC19MXTimelineDirectionOSo11MXRoomStateCtctFyAJSg_SC02__jK0VANSgtcfU_TA + 76
  13  SwiftMatrixSDK                      0x0000000100d1820a _T0So7MXEventCSgSC21__MXTimelineDirectionVSo11MXRoomStateCSgIegxyx_AceHIeyByyy_TR + 74
  14  SwiftMatrixSDK                      0x0000000100c48d22 -[MXEventListener notify:direction:andCustomObject:] + 162
  15  SwiftMatrixSDK                      0x0000000100c4d06a -[MXEventTimeline notifyListeners:direction:] + 407
  16  SwiftMatrixSDK                      0x0000000100c4c0ea -[MXEventTimeline addEvent:direction:fromStore:isRoomInitialSync:] + 1022
  17  SwiftMatrixSDK                      0x0000000100c4ba8d -[MXEventTimeline handlePaginationResponse:direction:] + 306
  18  SwiftMatrixSDK                      0x0000000100c4a78f __69-[MXEventTimeline paginate:direction:onlyFromStore:complete:failure:]_block_invoke + 177
  19  libdispatch.dylib                   0x0000000101a17cae _dispatch_call_block_and_release + 12
  20  libdispatch.dylib                   0x0000000101a0fd8f _dispatch_client_callout + 8
  21  libdispatch.dylib                   0x0000000101a1be09 _dispatch_main_queue_callback_4CF + 549
  22  CoreFoundation                      0x00007fff388c8c19 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
  23  CoreFoundation                      0x00007fff3888adfa __CFRunLoopRun + 2586
  24  CoreFoundation                      0x00007fff3888a153 CFRunLoopRunSpecific + 483
  25  UIFoundation                        0x00007fff5c581f03 -[NSHTMLReader _loadUsingWebKit] + 1902
  26  UIFoundation                        0x00007fff5c584e86 -[NSHTMLReader attributedString] + 22
  27  UIFoundation                        0x00007fff5c4f43a8 _NSReadAttributedStringFromURLOrData + 12388
  28  UIFoundation                        0x00007fff5c4f12b0 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 117
  29  Seaglass                            0x0000000100034d9d _T0So25NSMutableAttributedStringCAB10Foundation4DataV4data_s10DictionaryVySo012NSAttributedC0C6AppKitE24DocumentReadingOptionKeyVypG7optionss33AutoreleasingUnsafeMutablePointerVySo12NSDictionaryCSgGSg18documentAttributestKcfcTOTf4gXnnn_n + 173
  30  Seaglass                            0x00000001000350ca _T0SS8SeaglassE26toAttributedStringFromHTMLSo012NSAttributedD0CSC15NSTextAlignmentO7justify_tFTf4nx_n + 682
  31  Seaglass                            0x0000000100033ad9 _T0SS8SeaglassE26toAttributedStringFromHTMLSo012NSAttributedD0CSC15NSTextAlignmentO7justify_tF + 9
  32  Seaglass                            0x0000000100014ee9 _T08Seaglass22MainViewRoomControllerC05tableC0So6NSViewCSgSo07NSTableC0C_So0H6ColumnCSg7viewForSi3rowtFTf4gdnn_n + 5769
  33  Seaglass                            0x000000010000b82d _T08Seaglass22MainViewRoomControllerC05tableC0So6NSViewCSgSo07NSTableC0C_So0H6ColumnCSg7viewForSi3rowtFTo + 61
  34  AppKit                              0x00007fff35fb279b -[NSTableView(NSTableViewViewBased) _delegate_viewForTableColumn:row:] + 86
  35  AppKit                              0x00007fff35f2cec4 -[NSTableView(NSTableViewViewBased) makeViewForTableColumn:row:] + 87
  36  AppKit                              0x00007fff35f2c747 -[NSTableRowData _addViewToRowView:atColumn:row:] + 342
  37  AppKit                              0x00007fff35f2c421 -[NSTableRowData _addViewsToRowView:atRow:] + 211
  38  AppKit                              0x00007fff35f2aaa4 -[NSTableRowData _initializeRowView:atRow:] + 397
  39  AppKit                              0x00007fff3681696a -[NSTableRowData _preparedRowViewForRow:storageHandler:] + 154
  40  AppKit                              0x00007fff35f28ed1 -[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 392
  41  AppKit                              0x00007fff35f28c94 -[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 416
  42  AppKit                              0x00007fff36818ba3 -[NSTableRowData _updateVisibleRowEntries] + 1906
  43  AppKit                              0x00007fff368194d3 __59-[NSTableRowData _automaticRowHeightsUpdateVisibleRowViews]_block_invoke.1494 + 97
  44  AppKit                              0x00007fff368190ad -[NSTableRowData _keepTopRowStable:andDoWorkUntilDone:] + 535
  45  AppKit                              0x00007fff3681941d -[NSTableRowData _automaticRowHeightsUpdateVisibleRowViews] + 161
  46  AppKit                              0x00007fff35f27971 -[NSTableRowData updateVisibleRowViews] + 261
  47  AppKit                              0x00007fff35f27163 -[NSTableView layout] + 206
  48  AppKit                              0x00007fff366d0ad0 _NSViewLayout + 587
  49  AppKit                              0x00007fff35ecaeff -[NSView _layoutSubtreeWithOldSize:] + 437
  50  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  51  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070I                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  53  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  54  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  55  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  56  AppKit                              0x00007fff35ecb178 -[NSView _layoutSubtreeWithOldSize:] + 1070
  57  AppKit                              0x00007fff366d782c -[NSView _layoutSubtreeIfNeededAndAllowTemporaryEngine:] + 1380
  58  AppKit                              0x00007fff35ee86ef -[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 163
  59  AppKit                              0x00007fff35f53e83 -[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 268
  60  AppKit                              0x00007fff36705443 ___NSWindowGetDisplayCycleObserver_block_invoke.5896 + 67
  61  AppKit                              0x00007fff35f6455e __37+[NSDisplayCycle currentDisplayCycle]_block_invoke + 695
  62  QuartzCore                          0x00007fff43bfb8c7 _ZN2CA11Transaction19run_commit_handlersE18CATransactionPhase + 49
  63  QuartzCore                          0x00007fff43bfa389 _ZN2CA11Transaction6commitEv + 171
  64  AppKit                              0x00007fff3671ca72 __65+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayRefresh]_block_invoke + 283
  65  CoreFoundation                      0x00007fff388a8417 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
  66  CoreFoundation                      0x00007fff388a833f __CFRunLoopDoObservers + 527
  67  CoreFoundation                      0x00007fff3888a8b8 __CFRunLoopRun + 1240
  68  CoreFoundation                      0x00007fff3888a153 CFRunLoopRunSpecific + 483
  69  HIToolbox                           0x00007fff37b74d96 RunCurrentEventLoopInMode + 286
  70  HIToolbox                           0x00007fff37b74b06 ReceiveNextEventCommon + 613
  71  HIToolbox                           0x00007fff37b74884 _BlockUntilNextEventMatchingListInModeWithFilter + 64
  72  AppKit                              0x00007fff35e25a73 _DPSNextEvent + 2085
  73  AppKit                              0x00007fff365bbe34 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 3044
  74  AppKit                              0x00007fff35e1a885 -[NSApplication run] + 764
  75  AppKit                              0x00007fff35de9a72 NSApplicationMain + 804
  76  Seaglass                            0x0000000100003f69 main + 9
  77  libdyld.dylib                       0x00007fff606cb015 start + 1
  78  ???                                 0x0000000000000003 0x0 + 3
)


This doesn't make sense. As best as I can tell, this is all happening on the main thread.


Is this an actual bug or am I doing something stupid?


If seeing more of the codebase will help:

https://github.com/neilalexander/seaglass/blob/08c531f643245143cc2794bff738356b4241da1b/Seaglass/Extension/String.swift

https://github.com/neilalexander/seaglass/blob/08c531f643245143cc2794bff738356b4241da1b/Seaglass/Controller/MainViewRoomController.swift

I'm getting the crash:
Crashing on exception: insertRowsAtIndexes:withRowAnimation: can not happen while updating visible rows!
I accumulate changes to my table and then set them all at once via a timer.
However, the timer is firing during a run loop inside NSHTMLReader _loadUsingWebKit.
This is EXCEEDINGLY inconvenient for me.
I am unsure how I am supposed to tell if my timer can modify the values of the table or not.

What's happening is that you're using NSAttributedString to get a rich text string from HTML; this causes the system to internally use the WebKit engine to parse the HTML, and during this processing causes to runloop to get run, which triggers other code leading to internal inconsistencies.

Try and see if you can trigger the parsing before (or outside of) the code that alters the rows.

SIGABRT when using NSAttributedString.DocumentType.html
 
 
Q