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>
将第一列上一个选中的列数记录下来,那么第二列返回的列数个数就仍然是上一个省份的列数个数,所以不存在数组越界问题.
程序样式: