英文:
RxCocoa/RxSwift crash when accessing TableViewDataSourceNotSet tableView(_:cellForRowAt:)
问题
以下是代码部分的翻译:
// MyViewModel:
var itemList = BehaviorRelay(value: [MyItem]())
...
func loadData() {
var items = [...] // 加载项目
itemList.accept(items)
}
// ==========
// MyView:
var viewModel = MyViewModel()
func bindData() {
viewModel.itemList.bind(to: tableView.rx.items) { table, index, item in
if item.type == ... {
... // 基于项目元数据选择单元格类型
} else {
let cell = table.dequeueReusableCell(withIdentifier: "MyItemCell") as? MyItemCell {
cell.bindItem(item)
return cell
}
return new UITableViewCell()
}).disposed(by: viewModel.disposeBag)
}
// ==========
请注意,这只是代码的翻译,没有其他内容。如果你需要有关代码或问题的进一步解释,请提出具体的问题。
英文:
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:
// MyViewModel:
var itemList = BehaviorRelay(value: [MyItem]())
...
func loadData() {
var items = [...] // load items
itemList.accept(items)
}
// ==========
// 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)
}
// ==========
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?
答案1
得分: 1
以下是翻译好的部分:
bindData方法在每个页面出现时(willAppear)都会被调用,但不清楚为什么会崩溃以及如何重现/修复它。
上述情况是一个红旗。不应该在每个页面出现时进行绑定。最好的情况是会导致解绑,然后重新绑定。可能是这个情况在某些情况下让系统出现问题,其中表视图从之前安装的数据源调用numberOfRowsInSection
,然后在TableViewDataSourceNotSet
对象上调用cellForRowAt
。
您的绑定应该只发生一次。通常是在viewDidLoad中。
英文:
> The bindData method is called on every page appearance (willAppear) but it's not clear why it crashes and how to reproduce/fix it.
The above is a red flag. You should not be binding on every page appearance. Best case that is causing an unbinding and then rebinding. It could be that this is tripping up the system in some places where the table view is calling numberOfRowsInSection
from the previously installed data source, and then calling cellForRowAt
on the TableViewDataSourceNotSet
object.
Your binding should only happen once. Usually in the viewDidLoad.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论