前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS·CityPickerView省市区选择器出现奔溃纪实:三栏联动的时数据源数组越界(Xcode奔溃调试技巧)

iOS·CityPickerView省市区选择器出现奔溃纪实:三栏联动的时数据源数组越界(Xcode奔溃调试技巧)

作者头像
陈满iOS
发布2018-09-10 11:14:51
1.5K0
发布2018-09-10 11:14:51
举报
文章被收录于专栏:陈满iOS

iOS开发过程中,有时候一些第三方省市区位置选择器PickerView出现诡异bug:在快速同时分别滑动省、市、区各栏的时候,出现奔溃。这时候,你可以打个断点,查出问题所在。笔者碰到的原因是:数组越界。

  • 这里举例的第三方省市区选择器:YLAwesomePicker于Jun22, 2017年提交的版本(该问题目前已被改开源作者于Jul 31, 2017修复)。

  • 奔溃演示:

  • 奔溃情景:当省一栏滑到中国澳门,并同时滑动第二栏第三栏时,直接崩溃。

这里记录修复这种bug的一种方案。首先看看出问题的源代码,然后指出问题所在,并给出修复方案。

1. 问题代码

代码语言:javascript
复制
- (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. 问题所在

奔溃出现,在于这两句:

代码语言:javascript
复制
NSArray *array = _dataConfiguration.dataSource[@(component)];
YLAwesomeData *currentData = array[row];

如上所示,在获取array之前,并没有判断array是否为空数组?为空,array[row]能正常取值吗?所以添加一个判断即可:

代码语言:javascript
复制
if (array && array.count > 0) {
    ...
}

还有,array[row]中的row超过数组元素个数怎么办?继续追加判断:array.count>0且array.count>row。又有row>=0,故而如下即可:

代码语言:javascript
复制
if (array && array.count > row) {
    ...
}

完整修复代码

代码语言:javascript
复制
- (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. 选择异常类型

选择断点捕获类型,按下图设置即可。当然你也可以只选择OC或者Swift异常。

第二步

4. 小结

举一反三,不仅仅是位置选择器,在通过网络获取数据并为本地模型赋值的时候,如果没有严谨在赋值取值之前判断一些对象是否为空,就经常会出现这样的崩溃。

拓展文献

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.08.08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题代码
  • 2. 问题所在
  • 3. 定位奔溃技巧
  • 4. 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档