iOS開發(fā)過程中,有時候一些第三方省市區(qū)位置選擇器PickerView出現(xiàn)詭異bug:在快速同時分別滑動省缅疟、市分别、區(qū)各欄的時候遍愿,出現(xiàn)奔潰。這時候耘斩,你可以打個斷點沼填,查出問題所在。筆者碰到的原因是:數(shù)組越界括授。
-
這里舉例的第三方省市區(qū)選擇器:YLAwesomePicker于Jun22, 2017年提交的版本(該問題目前已被改開源作者于Jul 31, 2017修復)坞笙。
-
奔潰演示:
- 奔潰情景:當省一欄滑到澳門,并同時滑動第二欄第三欄時荚虚,直接崩潰薛夜。
這里記錄修復這種bug的一種方案。首先看看出問題的源代碼曲管,然后指出問題所在却邓,并給出修復方案。
1. 問題代碼
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if(component < _componentCount){
//remember the select data
NSArray *array = _dataConfiguration.dataSource[@(component)];
YLAwesomeData *currentData = array[row];
if(_tmpSelectedData.count > component){
_tmpSelectedData[component] = currentData;
}else{
[_tmpSelectedData addObject:currentData];
}
//ex: when select first component, the second to the last component data need refresh
for(NSInteger nextCom = component + 1; nextCom < _componentCount; nextCom++){
//reload data
NSArray *nextArray = [_dataConfiguration dataInComponent:nextCom selectedComponent:component row:row];
[pickerView reloadComponent:nextCom];
if(nextArray.count > 0){
NSInteger nextSelectRow = 0;
//remember the select data
YLAwesomeData *nextData = nextArray[nextSelectRow];
if(_tmpSelectedData.count > nextCom){
_tmpSelectedData[nextCom] = nextData;
}else{
[_tmpSelectedData addObject:nextData];
}
[pickerView selectRow:nextSelectRow inComponent:nextCom animated:NO];
}else{
if(_tmpSelectedData.count > nextCom){
//remove the last selected data
[_tmpSelectedData removeObjectsInRange:NSMakeRange(nextCom, _tmpSelectedData.count - nextCom)];
}
}
}
}
}
2. 問題所在
奔潰出現(xiàn)院水,在于這兩句:
NSArray *array = _dataConfiguration.dataSource[@(component)];
YLAwesomeData *currentData = array[row];
如上所示,在獲取array之前简十,并沒有判斷array是否為空數(shù)組檬某?為空,array[row]
能正常取值嗎螟蝙?所以添加一個判斷即可:
if (array && array.count > 0) {
...
}
還有恢恼,array[row]中的row超過數(shù)組元素個數(shù)怎么辦?繼續(xù)追加判斷:array.count>0且array.count>row胰默。又有row>=0场斑,故而如下即可:
if (array && array.count > row) {
...
}
完整修復代碼
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if(component < _componentCount){
//remember the select data
NSArray *array = _dataConfiguration.dataSource[@(component)];
if (array && array.count > row) {
YLAwesomeData *currentData = array[row];
if(_tmpSelectedData.count > component){
_tmpSelectedData[component] = currentData;
}else{
[_tmpSelectedData addObject:currentData];
}
//ex: when select first component, the second to the last component data need refresh
for(NSInteger nextCom = component + 1; nextCom < _componentCount; nextCom++){
//reload data
NSArray *nextArray = [_dataConfiguration dataInComponent:nextCom selectedComponent:component row:row];
[pickerView reloadComponent:nextCom];
if(nextArray.count > 0){
NSInteger nextSelectRow = 0;
//remember the select data
YLAwesomeData *nextData = nextArray[nextSelectRow];
if(_tmpSelectedData.count > nextCom){
_tmpSelectedData[nextCom] = nextData;
}else{
[_tmpSelectedData addObject:nextData];
}
[pickerView selectRow:nextSelectRow inComponent:nextCom animated:NO];
}else{
if(_tmpSelectedData.count > nextCom){
//remove the last selected data
[_tmpSelectedData removeObjectsInRange:NSMakeRange(nextCom, _tmpSelectedData.count - nextCom)];
}
}
}
}
}
}
3. 定位奔潰技巧
這里介紹一下為了定位奔潰原因的捕獲異常斷點技巧:
1. 添加異常斷點
左邊欄上面點擊斷點標簽,然后點擊左下角+號按鈕添加斷點:
2. 選擇異常類型
選擇斷點捕獲類型牵署,按下圖設(shè)置即可漏隐。當然你也可以只選擇OC或者Swift異常。
第二步
4. 小結(jié)
舉一反三奴迅,不僅僅是位置選擇器青责,在通過網(wǎng)絡(luò)獲取數(shù)據(jù)并為本地模型賦值的時候,如果沒有嚴謹在賦值取值之前判斷一些對象是否為空取具,就經(jīng)常會出現(xiàn)這樣的崩潰脖隶。
拓展文獻
- 刨根問底:OC 中如何判斷 NSArray 為空
http://www.reibang.com/p/ba11a53777e1