I'm starting to see the behavior described here:
Starting on iOS 16.2 for me (though the creator of the Stackoverflow thread started seeing in in 16.1.1.
Anyone else experiencing this?
I'm starting to see the behavior described here:
Starting on iOS 16.2 for me (though the creator of the Stackoverflow thread started seeing in in 16.1.1.
Anyone else experiencing this?
Based on the stack trace, it's crashing inside your code, specifically within the implementation of SettingsViewController.tableView(_:cellForRowAt:)
.
There's not enough information about what exactly is triggering the crash to say what the problem is, but I'd suggest looking carefully at your implementation of that method.
Thanks for the reply. That's not my post on Stackoverflow but I'm experiencing a similar crash that percolates up to -_createPreparedCellForGlobalRow:withIndexPath:willDisplay
The crash report for my app doesn't actually get to -tableView:cellForRowAtIndexPath: Instead I can see it all starts from my app checking the .visibleCells property on the table view:
0 CoreFoundation 0x19c789e48 __exceptionPreprocess + 164
1 libobjc.A.dylib 0x195a5b8d8 objc_exception_throw + 60
2 Foundation 0x19704a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x19eaa0888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x19ea744cc -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 596
5 UIKitCore 0x19e9adb28 -[UITableView _updateVisibleCellsNow:] + 1088
6 UIKitCore 0x19e9785e8 -[UITableView _visibleCellsUsingPresentationValues:] + 340
7 MyApp 0x103125120 -[MyTableViewSubclass checkIfLoadingCellIsIsVisible]
The checkIfLoadingCellIsIsVisible just enumerates the .visibleCells property on the table view, looking to see if a "loading more" cell is in the visible region of the table view. I've been unable to reliably reproduce the crash. Haven't managed to reproduce it at all when attached to the debugger. I picked up two of these crash reports today since I updated to iOS 16.2.
Thanks again for the reply (for some reason I didn't get an email notification for your Comment even though I'm "Watching" this thread." I just hit the crash again. I haven't hit it in a couple days (it isn't easy to reproduce). Exact same crash report as before just now:
** Last Exception Backtrace:
0 CoreFoundation 0x19c789e48 __exceptionPreprocess + 164 1 libobjc.A.dylib 0x195a5b8d8 objc_exception_throw + 60
2 Foundation 0x19704a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x19eaa0888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x19ea744cc -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 596
5 UIKitCore 0x19e9adb28 -[UITableView _updateVisibleCellsNow:] + 1088
6 UIKitCore 0x19e9785e8 -[UITableView _visibleCellsUsingPresentationValues:] + 34
7 MyApp 0x103125120 -[MyTableViewSubclass checkIfLoadingCellIsIsVisible]**
I don't see anywhere in my -tableView:celForRowAtIndexPath: method the possibility of my app returning nil unless for some strange reason UITableView -dequeueReusableCellWithIdentifier:forIndexPath: returned nil in some odd circumstance to me. I've been using my app for a long time on daily basis and this didn't start happening until after I updated to iOS 16.2, not sure if that's related though.
Hmm just hit it again. Slightly different code path this time before the -checkIfLoadingCellIsIsVisible method is called. This time after an object was removed from the model:
** Last Exception Backtrace: 0 CoreFoundation 0x19c789e48 __exceptionPreprocess + 164 1 libobjc.A.dylib 0x195a5b8d8 objc_exception_throw + 60
2 Foundation 0x19704a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x19eaa0888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x19ea744cc -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 596
5 UIKitCore 0x19e9adb28 -[UITableView _updateVisibleCellsNow:] + 1088
6 UIKitCore 0x19e9785e8 -[UITableView _visibleCellsUsingPresentationValues:] + 34
7 MyApp 0x103125120 -[MyTableViewSubclass checkIfLoadingCellIsIsVisible]
The -processRemovedObjectsNotification: method removes objects from the data source and reloads the table view (via -reloadData call). Then after reloading the table view it calls -checkIfLoadingCellIsIsVisible which enumerates the visibleCells to see if a loading more placeholder is in the visible region of the table view.
Definitely feels like something changed in UITableView in iOS 16.2 because I've been using this app for so long and it would seem highly unlikely for this to just be a coincidence. I still have a device on iOS 15. I haven't hit this crash on that device. But since going from iOS 16 to 16.2 on my iPhone I hit this like once or twice a day now.
I tried overriding -layoutSubviews in the table view subclass to see if I'm accessing visibleCells in the middle of table view layout:
-(void)layoutSubviews
{
self.isBuildingCellsInProgress = YES;
[super layoutSubviews];
self.isBuildingCellsInProgress = NO;
}
Then in my checkIfLoadingCellIsIsVisible method I check if isBuildingCellsInProgress property is YES on the table view, and if it is, return out and don't call the visibleCells getter. Unfortunately the isBuildingCellsInProgress is never YES when the checkIfLoadingCellIsIsVisible method is called. Haven't been able to isolate the issue. The only thing I can say for sure is that it started happening every so often since the iOS 16.2 update.
I do have a few of these tables views inside UITabBarController tabs. I'm thinking the issue may be triggered when this code is hit on a table view not currently in the window (the user is on another tab), but I can't say for sure because I'm unable to reproduce the issue when my app is attached to the debugger. When the "loading" cell is visible and the table view is not in the window my app just empties the data and reloads it on the next -viewDidAppear: call so enumerating the visibleCells when the table view is not in the window still provides value.
So I pushed an App update that uses the check above in layout subviews to block myself from accessing visibleCells during layoutSubviews (in my testing that wasn't showing to be occurring but since this crash is so rare I figured it might be the cause under some rare circumstances) so figured it was worth a shot. I've been using the app for two days now with the new update (quite a bit). I finally hit the crash again.
Crash reports show that my call to the visibleCells getter is that last part of my code being called. Then it goes to system code and then I crash (here's the call stack after I call the visibleCells getter)
0 CoreFoundation 0x19c789e48 __exceptionPreprocess + 164
1 libobjc.A.dylib 0x195a5b8d8 objc_exception_throw + 60
2 Foundation 0x19704a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x19eaa0888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x19ea744cc -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 596 5 UIKitCore 0x19e9adb28 -[UITableView _updateVisibleCellsNow:] + 1088
6 UIKitCore 0x19e9785e8 -[UITableView _visibleCellsUsingPresentationValues:] + 340
Anyone at Apple know what exception is being thrown here down this code path (or possible exceptions, if more than one is possible)? That'd at least point me in some kind of direction as to what (if anything) I can do to avoid this. Thanks in advance.
So I went ahead and pushed another update out with my second attempt at avoiding the crash without having much to go on. This time I avoid accessing the visibleCells property on the table view all together. Now I hit a crash again that bubbles up to _createPreparedCellForRowAtIndexPath:willDisplay: but this time the crash report includes a bit more:
CoreFoundation 0x1d1069e48 __exceptionPreprocess + 164
1 libobjc.A.dylib 0x1ca33b8d8 objc_exception_throw + 60
2 Foundation 0x1cb92a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x1d3380888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x1d344eeb4 -[UITableView _createPreparedCellForRowAtIndexPath:willDisplay:] + 68
5 UIKitCore 0x1d344ea9c -[UITableView _heightForRowAtIndexPath:] + 124
6 UIKitCore 0x1d344e938 -[UISectionRowData heightForRow:inSection:canGuess:] + 176
7 UIKitCore 0x1d3681394 -[UITableViewRowData heightForRow:inSection:canGuess:adjustForReorderedRow:] + 228
8 UIKitCore 0x1d328e8c4 -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:] + 304
9 UIKitCore 0x1d368091c -[UITableViewRowData rectForGlobalRow:heightCanBeGuessed:] + 112
10 UIKitCore 0x1d3681f70 -[UITableViewRowData globalRowsInRect:canGuess:] + 468
11 UIKitCore 0x1d36b43b8 -[_UITableViewUpdateSupport _faultInRealHeightsOfNeededElements] + 96
12 UIKitCore 0x1d36ee6c8 -[_UITableViewUpdateSupport _setupAnimations] + 36
13 UIKitCore 0x1d3524154 -[UITableView _updateWithItems:updateSupport:] + 832
14 UIKitCore 0x1d34e7ff0 -[UITableView _endCellAnimationsWithContext:] + 9900
15 UIKitCore 0x1d40ac6fc -[UITableView reconfigureRowsAtIndexPaths:] + 352
16 MyApp 0x104fcffa4 -[TableCellImageLoader didLoadImagesForCells] + 606116
--
Before the crash was triggered shortly after a reload data call on the table view when I accessed the visible cells property to determine the location of a "loading" cell. Now the crash is happening after my thumbnail loader loads some images and figures out the index paths needed to be reconfigured. The TableCellImageLoader uses indexPathsForVisibleRows to determine the index paths to reconfigure (it does not access the visibleCells property instead it looks through my model object using indexPathsForVisibleRows).
This crash report seems to imply that the crash may be related to the cell heights. My table view cells are self sizing (they override -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: and compute their size based on their content). My table view delegate does implement -tableView:estimatedHeightForRowAtIndexPath: (returning either a cached value or UITableViewAutomaticDimension) but I still don't really have a clue as to what the exception is about.
My delegate does not implement -tableView:heightForRowAtIndexPath: as the actual height is determined by the cell itself.
UITableview is now very unstable on iOS 16.2. I see nothing in the iOS release notes that documents any changes to UIKit in the minor updates (16.1 and 16.2) but I'm now getting periodic crashes every day (usually once or twice a day) in my own use of my app which I use extensively every day and have for a very long time. All the crashes start with a method call from my app to -reloadData or -reconfigureRowsAtIndexPaths:
and then stack trace looks like this:
Last Exception Backtrace: 0 CoreFoundation 0x1d1069e48 __exceptionPreprocess + 164
1 libobjc.A.dylib 0x1ca33b8d8 objc_exception_throw + 60
2 Foundation 0x1cb92a94c _userInfoForFileAndLine + 0
3 UIKitCore 0x1d3380888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572
4 UIKitCore 0x1d344eeb4 -[UITableView _createPreparedCellForRowAtIndexPath:willDisplay:] + 68
5 UIKitCore 0x1d344ea9c -[UITableView _heightForRowAtIndexPath:] + 124
6 UIKitCore 0x1d344e938 -[UISectionRowData heightForRow:inSection:canGuess:] + 176
7 UIKitCore 0x1d3681394 -[UITableViewRowData heightForRow:inSection:canGuess:adjustForReorderedRow:] + 228
8 UIKitCore 0x1d328e8c4 -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:] + 304
9 UIKitCore 0x1d368091c -[UITableViewRowData rectForGlobalRow:heightCanBeGuessed:] + 112
10 UIKitCore 0x1d3681f70 -[UITableViewRowData globalRowsInRect:canGuess:] + 468
11 UIKitCore 0x1d36b43b8 -[_UITableViewUpdateSupport _faultInRealHeightsOfNeededElements] + 96
12 UIKitCore 0x1d36ee6c8 -[_UITableViewUpdateSupport _setupAnimations] + 36
13 UIKitCore 0x1d3524154 -[UITableView _updateWithItems:updateSupport:] + 832
14 UIKitCore 0x1d34e7ff0 -[UITableView _endCellAnimationsWithContext:] + 9900
15 UIKitCore 0x1d40ac6fc -[UITableView reconfigureRowsAtIndexPaths:] + 352
This has severely damaged the quality of my app. I'm trying to mitigate these crashes by reducing/deferring my calls to mutate the table view but it seems essentially impossible because I can't tell the table view to do anything (reload, reconfigure, etc.) without risking one of these crashes. I'd open a TSI on this but I can't reproduce the issue in the debug environment and my project is very large (I can't reproduce in a simple sample obviously because I can' reproduce it in my real project when attached to the debugger). The crash happens usually after hours of daily use. Doesn't look like an invalid index path is being passed to the table view, especially considering that I get these crashes shortly after a call to -reloadData which is supposed to completely sync the table view to my data source.
I think someone with access to the UITableView source code can figure out what exception is being thrown here? I hope the changes made to UITableView will be reverted soon....
I can confirm that the exception being thrown here is "NSInternalInconsistencyException" with the Reason: UITableViewDataSource returned a nil cell for row at in index path"
NSAssertFile = UITableView.m
NSAssertLine = 16555
Since I couldn't reproduce this while attached to the debugger or when streaming logs from the app to Console I had to figure this out by writing the NSException related properties to a file in a function I pass to NSSetUncaughtExceptionHandler. Then I sent an Adhoc build to my device. After using the app for awhile I finally hit the crash. The crash report created looks identical to the ones I already shared in this thread and now I know the exception reason (not sure why the exception reason isn't included in the Crash Report?).
As I previously mentioned I don't see a code path in my -tableView:cellForRowAtIndexPath: method the possibility of my app returning nil unless for some strange reason UITableView -dequeueReusableCellWithIdentifier:forIndexPath: returned nil in some odd circumstance to me.
What's interesting is that neither -tableView:cellForRowAtIndexPath: nor -dequeueReusableCellWithIdentifier:forIndexPath: appears in the call stack on any of these crash reports so I'm getting the feeling the exception is being thrown improperly and this is a UITableView bug introduced in a minor OS update.
I'm going to add this to my -tableView:cellForRowAtIndexPath: method
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID forIndexPath:indexPath];
//configure cell..
if (cell == nil)
{
//This is not good! Why?
//Write a special file somewhere indicating that we have a nil cell right here.
}
return cell;
}
When the app crashes next time if this file exists I'll know for sure that UITableView improperly returned a nil cell to me..or if the exception message is completely bogus. But for now I got to get some sleep. This is not good.
So after many days of using a new Adhoc build of my app with the change to write a file in the event of getting a nil cell in -tableView:cellForRowAtIndexPath: I failed to reproduce the crash. Finally I hit the crash again today.
The file I attempt to write in -tableView:cellForRowAtIndexPath: does not exist on disk. The file I write to disk to capture the exception reason in my NSSetUncaughtExceptionHandler does exist. The exception reason is "UITableViewDataSource returned a nil cell for row at in index path"
The exception message reason/message appears to be bogus (unless I just hit the lottery and my attempt to write a file in -tableView:cellForRowAtIndexPath: failed with an error). I think a few possibilities are:
-UITableView exception message on this line 16555 is incorrect and needs to be changed to a proper exception message that truly indicates what's wrong.
-UITableView is really hitting its reuse queue but isn't properly retaining the cell it thinks it has and when it gets nil back from its internal implementation, it is throwing an exception incorrectly instead of asking the delegate to make a new instance.
-Maybe code triggered as part of inflight animations after delays/timers isn't properly cancelled when -reloadData is called and the table view is in a whacky state.
Or something else. Impossible for me to know without source code. In any case I have no idea how I can workaround this issue using only public API. If my -tableView:cellForAtIndexPath: isn't returning nil....there doesn't seem to be a way I can fix this.
Perhaps I finally resolved this. My last guess is that the UITableView for some reason started outliving the object I use to return a cell in -tableView:cellForRowAtIndexPath: which was never the case prior to iOS 16.2.
I made some changes, will need to test this longer to see if I finally got this fixed since the crash is pretty hard to reproduce.
@Macho Man ***** Savage Any luck in narrowing down the issue, because I see a lot of people getting this type of crashes in my app and I'm not able to reproduce this?
Yes I was able to resolve it. So in my case I have a dedicated object as the UITableViewDataSource that sits between the UIViewController and the UITableView.
The object that I use as the table view data source implements everything needed to populate the table view data, refreshing it automatically on model changes, etc. The only thing my table view data source doesn't do was provide a UITableView cell in -tableView:cellForRowAtIndexPath: method (instead it asks its delegate for the cell, which is the UIViewController) . My data source object is sort of like UITableViewDiffableDataSource in this way.
So what was happening is the UITableView AND the table view data source objects were occasionally outliving the UIViewController. Then when a model change notification is posted my datasource object asked the view controller for the cell in -tableView:cellForRowAtIndexPath: (but the view controller was already deallocated).
Never was able to reproduce it in debug mode. I removed the delegate-protocol from my data source object and captured the cell creation code in a block property and I haven't had a crash since.