iOS:省市联动的实现以及BUG的解决

plist文件的样式:


初步的代码实现(会出现问题!!):

<span style="font-size:18px;">#import "ViewController.h"
#import "MCProvinceModel.h"

@interface ViewController ()<UIPickerViewDelegate,UIPickerViewDataSource>
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@property(nonatomic,strong)NSArray *provinceArr;
@end

@implementation ViewController

- (NSArray *)provinceArr{
    if (!_provinceArr) {
        NSString *path = [[NSBundle mainBundle]pathForResource:@"provinces.plist" ofType:nil];
        NSArray *arr = [NSArray arrayWithContentsOfFile:path];
        NSMutableArray *nma = [NSMutableArray array];
        for (NSDictionary *dic in arr) {
            MCProvinceModel *model = [MCProvinceModel provinceWithDic:dic];
            [nma addObject:model];
        }
        _provinceArr = nma.copy;
    }
    return _provinceArr;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.pickerView.delegate = self;
    self.pickerView.dataSource = self;
}

#pragma mark -数据源方法
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    if (component == 0) {
        //返回第一列元素个数
        return self.provinceArr.count;
    }else{
        //第一列选中的行数
        NSInteger selectedRow = [pickerView selectedRowInComponent:0];
        MCProvinceModel *model = self.provinceArr[selectedRow];
        //返回第二列元素个数
        return model.cities.count;
    }
}

#pragma mark -代理方法
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    if (component == 0) {
        MCProvinceModel *model = self.provinceArr[row];
        return model.name;
    }else{
        //第一列选中的行数
        NSInteger selectedRow = [pickerView selectedRowInComponent:0];
        MCProvinceModel *model = self.provinceArr[selectedRow];
        return model.cities[row];
    }
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    //当第一列是选中状态的时候,刷新第二列并选中第二列第一行
    if (component == 0) {
        [pickerView selectRow:0 inComponent:1 animated:YES];
        [pickerView reloadComponent:1];
    }
}
@end</span>
这样实现的话起初看上去是没有问题的,但是当两列同时滚动的时候程序会崩溃,并且告诉你原因是数组越界.

那么问题出现在哪里呢?

当你滚动第一列的时候每经过一列这个方法都会返回一个列数索引,并且我们第二列的列数还依赖这个列数索引.

但是在didSelceteRow:(NSInteger)row inComponent:(NSInteger)component这个方法中我们只有在第一列选中之后才会刷新第二列的数据,所以发生了崩溃.

举个例子:比如说江西省有11个城市,当我们滚动第一列的时候正好经过天津,这时候第二行的列数就是1,但是第二行的数据还没有进行更新,所以可以滚动的列数是11个,当滚动超过1就提示了数组越界.

bug解决:

<span style="font-size:18px;">#import "ViewController.h"
#import "MCProvinceModel.h"

@interface ViewController ()<UIPickerViewDelegate,UIPickerViewDataSource>
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@property(nonatomic,strong)NSArray *provinceArr;
//记录第一列上一个选中的行数
@property(nonatomic,assign)NSInteger lastIndex;
@end

@implementation ViewController

- (NSArray *)provinceArr{
    if (!_provinceArr) {
        NSString *path = [[NSBundle mainBundle]pathForResource:@"provinces.plist" ofType:nil];
        NSArray *arr = [NSArray arrayWithContentsOfFile:path];
        NSMutableArray *nma = [NSMutableArray array];
        for (NSDictionary *dic in arr) {
            MCProvinceModel *model = [MCProvinceModel provinceWithDic:dic];
            [nma addObject:model];
        }
        _provinceArr = nma.copy;
    }
    return _provinceArr;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.pickerView.delegate = self;
    self.pickerView.dataSource = self;
}

#pragma mark -数据源方法
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    if (component == 0) {
        //返回第一列元素个数
        return self.provinceArr.count;
    }else{
        //根据第一列上一个选中的行数获取模型
        MCProvinceModel *model = self.provinceArr[self.lastIndex];
        //返回第二列元素个数
        return model.cities.count;
    }
}

#pragma mark -代理方法
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    if (component == 0) {
        MCProvinceModel *model = self.provinceArr[row];
        return model.name;
    }else{
        //根据第一列上一个选中的行数获取模型
        MCProvinceModel *model = self.provinceArr[self.lastIndex];
        return model.cities[row];
    }
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
    //当第一列是选中状态的时候,刷新第二列并选中第二列第一行
    if (component == 0) {
        //记录第一列选中的行数
        self.lastIndex = row;
        [pickerView selectRow:0 inComponent:1 animated:YES];
        [pickerView reloadComponent:1];
    }
}</span>

将第一列上一个选中的列数记录下来,那么第二列返回的列数个数就仍然是上一个省份的列数个数,所以不存在数组越界问题.

程序样式:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值