UITableViewController 在具有有效数据的 reloadData 上导致 NSRangeException
UITableViewController causes NSRangeException on reloadData with valid data
所以我在重新加载 tableView 时遇到了这个奇怪的崩溃。当类别数组为空时它加载正常,但是一旦我向数组添加值,我就会在重新加载 tableView 时收到 NSRangeException。即使数组中有 40 多个项目,它也会在索引 3 处崩溃。
public class CategorySearchMasterViewController: UITableViewController {
private let reuseIdentifier = "category_cell"
public weak var categoryDelegate: CategorySearchMasterViewControllerDelegate?
public var categoryDrilldownRequest: CategoryDrilldownRequest?
private var categories: [DrilldownCategory] = []
public override func viewDidLoad() {
super.viewDidLoad()
categoryDrilldownRequest?.fetchCategories(callback: { [weak self] (payload) in
self?.didReceivePayload(payload: payload)
})
}
private func didReceivePayload(payload: DrilldownPayload) {
categories = payload.categoriesList
categoryDelegate?.categorySearchMasterViewControllerDidReceiveSymbols(symbols: payload.symbolList)
tableView.reloadData()
}
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories.count
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: reuseIdentifier)
}
cell?.textLabel?.text = categories[indexPath.row].name
cell?.accessoryType = .disclosureIndicator
return cell!
}
public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let masterView = segue.destination as? CategorySearchMasterViewController {
masterView.categoryDrilldownRequest = categoryDrilldownRequest
}
}
}
堆栈跟踪:
2016-10-31 10:50:33.902 ProphetX[10884:12561505] \*** Terminating app due to uncaught exception 'NSRangeException', reason: '\*** -[\__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
\*** First throw call stack:
(
0 CoreFoundation 0x012a8212 __exceptionPreprocess + 194
1 libobjc.A.dylib 0x02a4ae66 objc_exception_throw + 52
2 CoreFoundation 0x011dc666 -[__NSArrayI objectAtIndex:] + 198
3 UIKit 0x03e1f5d2 -[UITableViewDataSource tableView:heightForRowAtIndexPath:] + 196
4 UIKit 0x03a35778 -[UITableViewController tableView:heightForRowAtIndexPath:] + 75
5 UIKit 0x0374ca37 -[UITableView _dataSourceHeightForRowAtIndexPath:] + 101
6 UIKit 0x039bbb39 __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 456
7 UIKit 0x039bae21 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4048
8 UIKit 0x039beefe -[UITableViewRowData numberOfRows] + 85
9 UIKit 0x037255c2 -[UITableView noteNumberOfRowsChanged] + 130
10 UIKit 0x03724ae6 -[UITableView reloadData] + 2071
11 ProphetX 0x0010962c _TFC8ProphetX34CategorySearchMasterViewControllerP33_1368510FCA7EF87AA17E4AFE1FCC1BF117didReceivePayloadfT7payloadVS_16DrilldownPayload_T_ + 1884
12 ProphetX 0x00108e48 _TFFC8ProphetX34CategorySearchMasterViewController11viewDidLoadFT_T_U_FVS_16DrilldownPayloadT_ + 152
13 ProphetX 0x0008762c _TFFC8ProphetX24CategoryDrilldownRequest15fetchCategoriesFT8callbackFVS_16DrilldownPayloadT__T_U_FGV9Alamofire12DataResponseSS_T_ + 844
14 ProphetX 0x0008779a _TPA__TFFC8ProphetX24CategoryDrilldownRequest15fetchCategoriesFT8callbackFVS_16DrilldownPayloadT__T_U_FGV9Alamofire12DataResponseSS_T_ + 74
15 Alamofire 0x00c107c6 _TTRXFo_oGV9Alamofire12DataResponseSS___XFo_iGS0_SS___ + 198
16 Alamofire 0x00c1087a _TPA__TTRXFo_oGV9Alamofire12DataResponseSS___XFo_iGS0_SS___ + 74
17 Alamofire 0x00c0c5c2 _TFFFC9Alamofire11DataRequest8responseuRxS_30DataResponseSerializerProtocolrFT5queueGSqCSo13DispatchQueue_18responseSerializerx17completionHandlerFGVS_12DataResponsewx16SerializedObject_T__DS0_U_FT_T_U_FT_T_ + 738
18 Alamofire 0x00c14c42 _TPA__TFFFC9Alamofire11DataRequest8responseuRxS_30DataResponseSerializerProtocolrFT5queueGSqCSo13DispatchQueue_18responseSerializerx17completionHandlerFGVS_12DataResponsewx16SerializedObject_T__DS0_U_FT_T_U_FT_T_ + 114
19 Alamofire 0x00c0c628 _TTRgRx9Alamofire30DataResponseSerializerProtocolrXFo___XFdCb___ + 40
20 libdispatch.dylib 0x056b73ee _dispatch_call_block_and_release + 15
21 libdispatch.dylib 0x056e2cc3 _dispatch_client_callout + 14
22 libdispatch.dylib 0x056c20ef _dispatch_main_queue_callback_4CF + 1755
23 CoreFoundation 0x0126878e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
24 CoreFoundation 0x0122b72f __CFRunLoopRun + 2319
25 CoreFoundation 0x0122abab CFRunLoopRunSpecific + 395
26 CoreFoundation 0x0122aa0b CFRunLoopRunInMode + 123
27 GraphicsServices 0x06891b4c GSEventRunModal + 177
28 GraphicsServices 0x068919c7 GSEventRun + 80
29 UIKit 0x035ae32b UIApplicationMain + 148
30 ProphetX 0x000f7351 main + 145
31 libdyld.dylib 0x0571d799 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
所以它似乎与 UITableViewController 的 objc 实现如何解释 Swift 数组有关。
如果我重写 heightForRowAtIndexPath 和 indentationLevelForRowAtIndexPath,那么一切正常,但如果我保留任一方法的默认实现,它就会崩溃。
我最终选择了带有 UITableView 元素的普通 UIViewController,以实现布局灵活性。增加的副作用是没有默认实现崩溃。
所以我在重新加载 tableView 时遇到了这个奇怪的崩溃。当类别数组为空时它加载正常,但是一旦我向数组添加值,我就会在重新加载 tableView 时收到 NSRangeException。即使数组中有 40 多个项目,它也会在索引 3 处崩溃。
public class CategorySearchMasterViewController: UITableViewController {
private let reuseIdentifier = "category_cell"
public weak var categoryDelegate: CategorySearchMasterViewControllerDelegate?
public var categoryDrilldownRequest: CategoryDrilldownRequest?
private var categories: [DrilldownCategory] = []
public override func viewDidLoad() {
super.viewDidLoad()
categoryDrilldownRequest?.fetchCategories(callback: { [weak self] (payload) in
self?.didReceivePayload(payload: payload)
})
}
private func didReceivePayload(payload: DrilldownPayload) {
categories = payload.categoriesList
categoryDelegate?.categorySearchMasterViewControllerDidReceiveSymbols(symbols: payload.symbolList)
tableView.reloadData()
}
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories.count
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: reuseIdentifier)
}
cell?.textLabel?.text = categories[indexPath.row].name
cell?.accessoryType = .disclosureIndicator
return cell!
}
public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let masterView = segue.destination as? CategorySearchMasterViewController {
masterView.categoryDrilldownRequest = categoryDrilldownRequest
}
}
}
堆栈跟踪:
2016-10-31 10:50:33.902 ProphetX[10884:12561505] \*** Terminating app due to uncaught exception 'NSRangeException', reason: '\*** -[\__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
\*** First throw call stack:
(
0 CoreFoundation 0x012a8212 __exceptionPreprocess + 194
1 libobjc.A.dylib 0x02a4ae66 objc_exception_throw + 52
2 CoreFoundation 0x011dc666 -[__NSArrayI objectAtIndex:] + 198
3 UIKit 0x03e1f5d2 -[UITableViewDataSource tableView:heightForRowAtIndexPath:] + 196
4 UIKit 0x03a35778 -[UITableViewController tableView:heightForRowAtIndexPath:] + 75
5 UIKit 0x0374ca37 -[UITableView _dataSourceHeightForRowAtIndexPath:] + 101
6 UIKit 0x039bbb39 __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 456
7 UIKit 0x039bae21 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4048
8 UIKit 0x039beefe -[UITableViewRowData numberOfRows] + 85
9 UIKit 0x037255c2 -[UITableView noteNumberOfRowsChanged] + 130
10 UIKit 0x03724ae6 -[UITableView reloadData] + 2071
11 ProphetX 0x0010962c _TFC8ProphetX34CategorySearchMasterViewControllerP33_1368510FCA7EF87AA17E4AFE1FCC1BF117didReceivePayloadfT7payloadVS_16DrilldownPayload_T_ + 1884
12 ProphetX 0x00108e48 _TFFC8ProphetX34CategorySearchMasterViewController11viewDidLoadFT_T_U_FVS_16DrilldownPayloadT_ + 152
13 ProphetX 0x0008762c _TFFC8ProphetX24CategoryDrilldownRequest15fetchCategoriesFT8callbackFVS_16DrilldownPayloadT__T_U_FGV9Alamofire12DataResponseSS_T_ + 844
14 ProphetX 0x0008779a _TPA__TFFC8ProphetX24CategoryDrilldownRequest15fetchCategoriesFT8callbackFVS_16DrilldownPayloadT__T_U_FGV9Alamofire12DataResponseSS_T_ + 74
15 Alamofire 0x00c107c6 _TTRXFo_oGV9Alamofire12DataResponseSS___XFo_iGS0_SS___ + 198
16 Alamofire 0x00c1087a _TPA__TTRXFo_oGV9Alamofire12DataResponseSS___XFo_iGS0_SS___ + 74
17 Alamofire 0x00c0c5c2 _TFFFC9Alamofire11DataRequest8responseuRxS_30DataResponseSerializerProtocolrFT5queueGSqCSo13DispatchQueue_18responseSerializerx17completionHandlerFGVS_12DataResponsewx16SerializedObject_T__DS0_U_FT_T_U_FT_T_ + 738
18 Alamofire 0x00c14c42 _TPA__TFFFC9Alamofire11DataRequest8responseuRxS_30DataResponseSerializerProtocolrFT5queueGSqCSo13DispatchQueue_18responseSerializerx17completionHandlerFGVS_12DataResponsewx16SerializedObject_T__DS0_U_FT_T_U_FT_T_ + 114
19 Alamofire 0x00c0c628 _TTRgRx9Alamofire30DataResponseSerializerProtocolrXFo___XFdCb___ + 40
20 libdispatch.dylib 0x056b73ee _dispatch_call_block_and_release + 15
21 libdispatch.dylib 0x056e2cc3 _dispatch_client_callout + 14
22 libdispatch.dylib 0x056c20ef _dispatch_main_queue_callback_4CF + 1755
23 CoreFoundation 0x0126878e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
24 CoreFoundation 0x0122b72f __CFRunLoopRun + 2319
25 CoreFoundation 0x0122abab CFRunLoopRunSpecific + 395
26 CoreFoundation 0x0122aa0b CFRunLoopRunInMode + 123
27 GraphicsServices 0x06891b4c GSEventRunModal + 177
28 GraphicsServices 0x068919c7 GSEventRun + 80
29 UIKit 0x035ae32b UIApplicationMain + 148
30 ProphetX 0x000f7351 main + 145
31 libdyld.dylib 0x0571d799 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
所以它似乎与 UITableViewController 的 objc 实现如何解释 Swift 数组有关。
如果我重写 heightForRowAtIndexPath 和 indentationLevelForRowAtIndexPath,那么一切正常,但如果我保留任一方法的默认实现,它就会崩溃。
我最终选择了带有 UITableView 元素的普通 UIViewController,以实现布局灵活性。增加的副作用是没有默认实现崩溃。