RxSwift
RxSwift copied to clipboard
RxCocoa/RxSwift crash when accessing TableViewDataSourceNotSet tableView(_:cellForRowAt:)
Short description of the issue:
I'm using RxCocoa and RxSwift to render a UITableView against an array provided by a BehaviorRelay. The code to bind the data is below. In most cases it works just fine but in some rare cases which I cannot reproduce the app crashes with the following stacktrace, reported by a few Firebase uses:
Crashed: com.apple.main-thread
0 libswiftCore.dylib 0x37d7c _assertionFailure(_:_:file:line:flags:) + 312
1 mycoolapp 0x8aa968 @objc TableViewDataSourceNotSet.tableView(_:cellForRowAt:) + 84 (RxCocoa.swift:84)
2 mycoolapp 0x8aae30 @objc RxTableViewDataSourceProxy.tableView(_:cellForRowAt:) + 64 (RxTableViewDataSourceProxy.swift:64)
3 UIKitCore 0x14b75c -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 808
4 UIKitCore 0x219c9c -[UITableView _createPreparedCellForRowAtIndexPath:willDisplay:] + 68
5 UIKitCore 0x219884 -[UITableView _heightForRowAtIndexPath:] + 124
6 UIKitCore 0x219720 -[UISectionRowData heightForRow:inSection:canGuess:] + 176
7 UIKitCore 0x44c328 -[UITableViewRowData heightForRow:inSection:canGuess:adjustForReorderedRow:] + 228
8 UIKitCore 0x5952c -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:] + 304
9 UIKitCore 0x44b8b0 -[UITableViewRowData rectForGlobalRow:heightCanBeGuessed:] + 112
10 UIKitCore 0x14b378 -[UITableView _prefetchCellAtGlobalRow:aboveVisibleRange:] + 240
11 UIKitCore 0x14b264 __48-[UITableView _configureCellPrefetchingHandlers]_block_invoke + 52
12 UIKitCore 0x2186a8 -[_UITableViewPrefetchContext updateVisibleIndexRange:withContentOffset:] + 2100
13 UIKitCore 0x81be8 -[UITableView _updateCycleIdleUntil:] + 168
14 UIKitCore 0x811ac ___UIUpdateCycleNotifyIdle_block_invoke + 612
15 libdispatch.dylib 0x2460 _dispatch_call_block_and_release + 32
16 libdispatch.dylib 0x3f88 _dispatch_client_callout + 20
17 libdispatch.dylib 0x127f4 _dispatch_main_queue_drain + 928
18 libdispatch.dylib 0x12444 _dispatch_main_queue_callback_4CF + 44
19 CoreFoundation 0x9a6c8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
20 CoreFoundation 0x7c02c __CFRunLoopRun + 2036
21 CoreFoundation 0x80eb0 CFRunLoopRunSpecific + 612
22 GraphicsServices 0x1368 GSEventRunModal + 164
23 UIKitCore 0x3a1668 -[UIApplication _run] + 888
24 UIKitCore 0x3a12cc UIApplicationMain + 340
25 mycoolapp. 0x1d8564 main + 23 (AppDelegate.swift:23)
26 ??? 0x1b3d9c960 (Missing)
The crash is hard to reproduce (I wasn't able to) but it's affects multiple users. The bindData method is called once at viewDidLoad, and I call loadData on every page appearance (willAppear, return back from another page or app activation deactivation) but it's not clear why it crashes and how to reproduce/fix it.
The crash is coming from TableViewDataSourceNotSet which seems to be set by the RxCocoa/RxSwift framework and crashes when cell for an item is requested. I'm not setting that custom dataSource explicitly anywhere. Any ideas how I can prevent this from happening?
Expected outcome:
App renders the table and no crashes are reported by users in Firebase
What actually happens:
App renders the table but a few users report crashes TableViewDataSourceNotSet
Self contained code example that reproduces the issue:
// MyViewModel:
var itemList = BehaviorRelay(value: [MyItem]())
...
func loadData() {
var items = [...] // load items
itemList.accept(items) //always happens on main thread
}
// ==========
// MyView:
var viewModel = MyViewModel()
func bindData() {
viewModel.itemList.bind(to: tableView.rx.items) { table, index, item in
if item.type == ... {
... // pick cell type based on the item metadata
} else {
let cell = table.dequeueReusableCell(withIdentifier: "MyItemCell") as? MyItemCell {
cell.bindItem(item)
return cell
}
return new UITableViewCell()
}).disposed(by: viewModel.disposeBag)
}
// ==========
RxSwift/RxCocoa/RxBlocking/RxTest version/commit
v5.1.1
Platform/Environment
- [x] iOS
- [ ] macOS
- [ ] tvOS
- [ ] watchOS
- [ ] playgrounds
How easy is to reproduce? (chances of successful reproduce after running the self contained code)
- [ ] easy, 100% repro
- [ ] sometimes, 10%-100%
- [ ] hard, 2% - 10%
- [x] extremely hard, %0 - 2%
Xcode version:
14.3
:warning: Fields below are optional for general issues or in case those questions aren't related to your issue, but filling them out will increase the chances of getting your issue resolved. :warning:
Installation method:
- [x] CocoaPods
- [ ] Carthage
- [ ] Git submodules
I have multiple versions of Xcode installed: (so we can know if this is a potential cause of your issue)
- [ ] yes (which ones)
- [x] no
Level of RxSwift knowledge: (this is so we can understand your level of knowledge and formulate the response in an appropriate manner)
- [ ] just starting
- [ ] I have a small code base
- [x] I have a significant code base
In order for this to happen, something needs to be returning a positive, non-zero, value from numberOfRowsInSection (tableViewDataSourceNotSet returns 0 in this function) then whatever data source is returning that non-zero value is being removed so that tableViewDataSourceNotSet's cellForRowAt gets called.
Apple made some internal changes to how table views work (i.e., added a bug to table views) recently, which is fixed in the latest version of RxCocoa... Your error doesn't seem to be related to that issue, but it is a good idea for you to update to the latest versions of RxSwift and RxCocoa.
Note that your code sample is not self-contained. Also note that this issue is also being discussed here (https://stackoverflow.com/questions/75952981/rxcocoa-rxswift-crash-when-accessing-tableviewdatasourcenotset-tableview-cellf)
@alexeystrakh Any solutions for this? I am facing the same crashes in my firebase dashboard
Can one of you create self-contained code sample?
I can work on the self-contained code sample but see no value in it, because the code follows the guidelines and works in 99.99% cases. Basically when you run it, you wont see any crashes and most likely won't be able to reproduce. I believe the issue is in either UIKit or RxCocoa as the stack trace points there as should be handled respectively.
Meanwhile, I will create a sample project to reflect the code structure and the rx bindings.
Since this has never come up before in the past 8 years, either you are doing something wrong, or Apple has indeed changed something inside UIKit (this wouldn't be the first time they've done that) or there is a specific issue within Firebase.
So questions:
- What version(s) of iOS are experiencing these crashes?
- Are these sorts of crashes happening even when Firebase is not involved?
Can you provide analytics that can answer the first question? Can you remove Firebase from the equation to see if that fixes the problem?
Here we go, the self-contained solution: https://github.com/alexeystrakh/rxswift-tablecrash
What version(s) of iOS are experiencing these crashes?
iOS 15 and iOS 16 (foreground only)
Are these sorts of crashes happening even when Firebase is not involved?
Without Firebase it will be hard to say, because they are only reported by Firebase, I cannot reproduce them locally.
For me, the Firebase crash analysis is attached below for the iOS versions
@danielt1263 where you able to confirm an issue or find some workaround for this crash?
I was not.