Exception… Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed

On iPadOS and iOS13 on a call to visibleCells on a UITableView ( on code which works fine on iOS9 to iOS12 ) I get an exception with the message


Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed.


Searching on the web gives me no hits for this exact message, so I suspect the message itself is new or changed.



Now the general gist of the message is fairly clear, but the specifics and but how one is expected to avoid this in a multithreaded application are far from clear.


For example ...what sort of changes qualify,


For example ... the user may rotate the device, a redisplay may be caused by incoming data. Are these now to be expected to crash your application?


Maybe there is a new threading model / usage requirement that I don't know about, yet.


Synchronising on the UITableView itself doesn't help.


What am I missing



And Yes, I can avoid the problem by catching the error and backing off until I succeed. But the hit on performance is eyewatering. And it's horrible.

Hey tylerf!

Been experiencing crash all day with exception. Please help


2019-10-03 13:51:21.910027-0400 Proteus[69427:3583092] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Requested the number of rows for section (1) which is out of bounds.'

*** First throw call stack:

(

0 CoreFoundation 0x00007fff23b98bde __exceptionPreprocess + 350

1 libobjc.A.dylib 0x00007fff503b5b20 objc_exception_throw + 48

2 CoreFoundation 0x00007fff23b98958 +[NSException raise:format:arguments:] + 88

3 Foundation 0x00007fff255eb7be -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 166

4 UIKitCore 0x00007fff47381d87 -[UITableViewRowData numberOfRowsInSection:] + 436

5 Proteus 0x000000010952959f $s7Proteus26ElasticSearchTableViewCellC15prepareForReuseyyF + 127

6 Proteus 0x0000000109529658 $s7Proteus26ElasticSearchTableViewCellC15prepareForReuseyyFTo + 24

7 UIKitCore 0x00007fff47346d68 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 181

8 UIKitCore 0x00007fff473473fa -[UITableView _dequeueReusableCellWithIdentifier:forIndexPath:usingPresentationValues:] + 153

9 UIKitCore 0x00007fff4734732d -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:] + 91

10 Proteus 0x0000000109331cac $s7Proteus17ElasticControllerC9tableView_12cellForRowAtSo07UITableE4CellCSo0jE0C_10Foundation9IndexPathVtF + 2700

11 Proteus 0x0000000109332100 $s7Proteus17ElasticControllerC9tableView_12cellForRowAtSo07UITableE4CellCSo0jE0C_10Foundation9IndexPathVtFTo + 128

12 UIKitCore 0x00007fff47360e4b -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 787

13 UIKitCore 0x00007fff4732a3c6 -[UITableView _updateVisibleCellsNow:] + 3081

14 UIKitCore 0x00007fff4734a318 -[UITableView layoutSubviews] + 163

15 UIKitCore 0x00007fff47636722 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2478

16 QuartzCore 0x00007fff2b030ef9 -[CALayer layoutSublayers] + 255

17 QuartzCore 0x00007fff2b0358ff _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 517

18 QuartzCore 0x00007fff2b041fe4 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 80

19 QuartzCore 0x00007fff2af8a4a8 _ZN2CA7Context18commit_transactionEPNS_11TransactionEd + 324

20 QuartzCore 0x00007fff2afbfab3 _ZN2CA11Transaction6commitEv + 643

21 QuartzCore 0x00007fff2afc041a _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 76

22 CoreFoundation 0x00007fff23afaeb7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23

23 CoreFoundation 0x00007fff23af594e __CFRunLoopDoObservers + 430

24 CoreFoundation 0x00007fff23af5fca __CFRunLoopRun + 1514

25 CoreFoundation 0x00007fff23af56b6 CFRunLoopRunSpecific + 438

26 GraphicsServices 0x00007fff3815cbb0 GSEventRunModal + 65

27 UIKitCore 0x00007fff47162a67 UIApplicationMain + 1621

28 Proteus 0x00000001092f542a main + 58

29 libdyld.dylib 0x00007fff5123bcf5 start + 1

)

libc++abi.dylib: terminating with uncaught exception of type NSException

(lldb)

What're the guidelines for dealing with this in a tabbed application w/ an active NSFetchedResultsController? We have a Notifications tab that periodically fetches data in the background, which can trigger the tab's NSFetchedResultsController even when that tab isn't currently selected. It seems that UITableView.beginUpdates(), invoked via my NSFetchedResultsControllerDelegate callback, throws this warning.

I had this problem in two places.


I used the suggestion in the console message to create a symbolic break on UITableViewAlertForCellForRowAtIndexPathAccessDuringUpdate and then clicked on the white bolded references in the (backtrace window, which was the breakpoint navigator before running the simulator). These took me right to the line in my code with the issue.


I missed this 'click on the white bolded line in backtrace' previous attempts at debugging this and like this issue.


In one case, in the viewForHeaderInSection func, I had some UI element based on the presence of a row for that section or not. I changed that to some other attribute not based on the related formed/forming cell.


In the other case, I had similarly put a condition in the canEditRowAt that would test if the `tableView.cellForRow(at:)` was of a certain class. Unhappy form. Replaced it with a condition based on a non-UI element and issue... gone.


Nowhere did I use visibleCells explicitly, but I did analyze a visible cell. The point: don't be so literal in interpreting a console message.

Exception… Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed
 
 
Q