美文网首页iOS开发iOS学习开发iOS程序猿
iOS·CityPickerView省市区选择器出现奔溃纪实:三

iOS·CityPickerView省市区选择器出现奔溃纪实:三

作者: 小码僧 | 来源:发表于2017-08-08 16:12 被阅读216次

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

    • 这里举例的第三方省市区选择器: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. 问题所在

    奔溃出现,在于这两句:

    NSArray *array = _dataConfiguration.dataSource[@(component)];
    YLAwesomeData *currentData = array[row];
    

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

    if (array && array.count > 0) {
        ...
    }
    

    还有,array[row]中的row超过数组元素个数怎么办?继续追加判断: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. 选择异常类型

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


    第二步

    4. 小结

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

    拓展文献

    相关文章

      网友评论

        本文标题:iOS·CityPickerView省市区选择器出现奔溃纪实:三

        本文链接:https://www.haomeiwen.com/subject/wqwtrxtx.html