UIPIckerView现实城市选择

实现城市选择,选中省时,后来自动显示相对应的城市,并且下面会打印出来对应的省和城市

.

 因为plist里面是一个一个的字典.

1.字典转模型

HMCities.h

#import <Foundation/Foundation.h>
@interface HMCities : NSObject
@property(nonatomic, strong)NSArray *cities;
@property(nonatomic, copy)NSString *name;
-(instancetype)initWithDict:(NSDictionary *)dict;
+(instancetype)citiesWithDict:(NSDictionary *)dict;
@end

HMCities.m

#import "HMCities.h"
@implementation HMCities
-(instancetype)initWithDict:(NSDictionary *)dict
{
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
+(instancetype)citiesWithDict:(NSDictionary *)dict
{
    return [[self alloc]initWithDict:dict];
}
@end

 第二步:懒加载数据

#import "ViewController.h"
#import "HMCities.h"
@interface ViewController ()
@property(nonatomic, strong)NSArray *cities;
@end
@implementation ViewController
#pragma mark /*******************懒加载数据******************/
-(NSArray *)cities
{
    if (_cities == nil) {
        NSString *path = [[NSBundle mainBundle]pathForResource:@"cities.plist" ofType:nil];
        NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
        NSMutableArray *arrayM = [NSMutableArray array];
        for (NSDictionary *dict in arrayDict) {
            HMCities *cities = [HMCities citiesWithDict:dict];
            [arrayM addObject:cities];
        }
        _cities = arrayM;
    }
    return _cities;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%@",self.cities);
}
@end

3.搭建界面  上面是pickerView. 下面有两个tableView.  设置控件的约束

4.  设置pickerView的数据源和代理统一为View Controller,实现数据源方法和代理方法.

#pragma mark /******************UIPickerView的数据源方法****************/
//返回有多少列
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 2;
}
//返回每列有多少行,因为有两列数据,而且第1列有多少行,是根据第0列被选中那一行决定的.所以需要先进行判断
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == 0) {//表示第0列被选中,(省份被选中)
        //返回第0列有多少行
        return self.cities.count;
    }else{//表示第1列被选中,(城市)
        //先要使用selectedRowInComponent方法获取第0列的那一行被选中,
        NSInteger idx_row = [self.pickerView selectedRowInComponent:0];
        //获取第0列被选中行的模型
        HMCities *model = self.cities[idx_row];
        //返回第1列有多少行
        return model.cities.count;
    }
}

5.实现功能

1.当省份发生改变时,城市对应的发生改变.

2.省份发生改变,城市对应发生改变时,显示第一个城市.

#pragma mark /*******************UIPickerView代理方法******************/
//返回每一行的数据
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    if (component == 0) {    //表示索引为1的列被选中--要的是城市的名称
        HMCities *model = self.cities[row];//获取数据模型
        return model.name;   //返回对应行要显示的数据
    } else                   //表示索引为1的列被选中,要的是城市的名称
    {   //获取第0列哪一行被选中(那个省份被选中)
        NSInteger idx_row = [self.pickerView selectedRowInComponent:0];
        //获取当前第0列选中的省份模型
        HMCities *model = self.cities[idx_row];
        return model.cities[row];
    }
}
//选中行改变事件,改变第0列数据时,第1列要相对应的显示不同的数据(第0列选择省份,第1列显示对应的城市)
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    if (component == 0) {//表示第0列发生了改变,用户重新选择了第0列的数据(省份发生变化)
        //刷新索引为1列中的数据,只有第1列发生变化,只刷新第1列的数据就可以.
        [pickerView reloadComponent:1];
        
        //刷新所有数据
        //[pickerView reloadAllComponents];
        
        //设置当第0列发生改变时,第1列显示第0行的数据(省份发生变化时,显示第一个城市名称)
        //设置索引为1的列的第0行被选中
        [pickerView selectRow:0 inComponent:1 animated:YES];
    }
    
}

6.实现功能

1.选中省份和城市时,把数据显示到对象的label上

1.1创建省份和城市的属性

//省份
@property (weak, nonatomic) IBOutlet UILabel *provinceLabel;
//城市
@property (weak, nonatomic) IBOutlet UILabel *cityLabel;

把方法实现到didSelectRow方法里面

//获取当前选中行的数据,并且将选中行的数据显示到对应的label上
    //获取选中的省份
    NSInteger idx_province = [pickerView selectedRowInComponent:0];
    HMCities *model = self.cities[idx_province];
    self.provinceLabel.text = model.name;
    
    //选中城市
    //获取第1列被选中那一行
    NSInteger idx_city = [pickerView selectedRowInComponent:1];
    self.cityLabel.text = model.cities[idx_city];

让程序一开始运行,label就显示数据.

方法实现到viewDidLoad方法里面

- (void)viewDidLoad {
    [super viewDidLoad];
    //NSLog(@"%@",self.cities);
    //手动设置选中那一行
    [self.pickerView selectRow:0 inComponent:0 animated:YES];
    [self.pickerView selectRow:0 inComponent:1 animated:YES];
    
    //手动调用didSelectRow方法,让程序一开始运行,label就显示数据.
    [self pickerView :self.pickerView didSelectRow:0 inComponent:0];
    [self pickerView :self.pickerView didSelectRow:0 inComponent:1];
    
}

功能全部实现完成,最后的Bug.当省份一列正在运行时,在运行城市一列程序就会崩溃. 

1.产生Bug的原因

1. 通过设置全局断点找到错误。
2. 先看几个知识点:
1》
titleForRow方法什么时候执行:在滚动的过程当中会一直被执行
2》
didSelectRow方法什么时候执行:当滚动完毕, 已经确定哪行被选中后, 会调用didSelectRow方法。在一直滚动的过程当中, didSelectRow方法时不会被调用的。
3》
numberOfRowsInComponent方法什么时候执行:因为在didSelectRow方法中调用了[pickerView reloadComponent:1];方法来刷新数据。而刷新数据的含义就是重新调用数据源方法和代理方法,所以numberOfRowsInComponent也会被调用
4》
[self.pickerView selectedRowInComponent:0];这个方法返回的是, 给定的列中当前选中的行的索引。(注意: 在picker view滚动的过程当中(滚动还没有停止, 还没有触发DidSelectRow方法),此时selectedRowInComponent方法, 返回的就是当前行中所显示的哪行的索引。

当省份在运行时,还没有确定被选中的具体省份.这个时候运行城市列表.  城市一列会发生改变, 城市列不能和省份列相对应. 这样会造成数据越界.

同理(当运行城市列表时,运行省份列表也会发生程序崩溃).

解决:创建一个记录当前选中省份的索引,城市列通过索引获取当前城市列的行,当省份列在运行时,城市列不受干扰,只有在省份列停止时,调用didSelectRow方法,才会改变新的索引.

创建记录当前选中省份的索引属性

//用来记录当前选中省份的索引
@property(nonatomic, assign) NSInteger idx_row;

在numberOfRowsInComponent方法中,把选中省份的索引记录下来

//先要使用selectedRowInComponent方法获取第0列的那一行被选中,
        NSInteger idx_row = [self.pickerView selectedRowInComponent:0];
        
        //将当前选中的省份的索引记录下来
        self.idx_row = idx_row;

在titleForRow方法中,返回每一行数据时,通过过记录的索引获取当前第0列选中的省份模型

 //获取当前第0列选中的省份模型
        HMCities *model = self.cities[self.idx_row];
        return model.cities[row];

在didSelectRow方法中,设置table数据时,使用记录的索引设置要显示的省份.

//获取当前选中行的数据,并且将选中行的数据显示到对应的label上
    //获取选中的省份
    //NSInteger idx_province = [pickerView selectedRowInComponent:0];
    NSInteger idx_province = self.idx_row;
    HMCities *model = self.cities[idx_province];
    self.provinceLabel.text = model.name;

 

转载于:https://www.cnblogs.com/Iosw/p/4867365.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值