一般做iOS开发,或多或少会接触到地址选择这个控件,最佳方法就是自定义UIPickerView,实现控件的几个代理方法!前段时间接收一个项目,用了别人封装的一个地址选择器,测试测出了很多问题,首先,三个控件不能联动,会出现广东省沈阳市天河区这样的错误。其次,测试要求,选完地址后,下次再弹出界面,没有显示之前选择的地址。最后,看了很多Demo,都是直接用NSArray,NSDictionary来处理数据,写起来太冗长,所以决定自己封装一下,代码看上去十分优雅!
首先数据结构,省,市,区是字典结构,而且key都相同,即省有i,n,s三个键值对,依次对应编码,名字,和下级(最后一级区没有s这个键,因为最多到区这一级)是三重嵌套类型,即最外层是省份字典数组,省份
因为涉及到多层嵌套,如果不用模型来处理,要一层一层去通过字典键取值,代码会很冗余,而且容易出错。所以一般都会将字典转换成模型。这里用到YYModel开源库,
转换成模型后就可以通过点语法来访问,十分方便
这里会涉及到YYModel一个高级用法,即多层嵌套模型一键转换,可以去GitHub上参考相关资料
.h文件我是这样定义的
s加上类型限制,主要是参考了swift强类型语言特点,
.m文件
转换过程如图:
接下来三个代理方法,这个时候就可以提现模型的方便之处,还有指定数组类型的好处了。
总共返回三组。
每组返回多少数据。
每组返回的标题
接下来是联动处理
下面是显示上次地址的逻辑
- (void)showDefaultAddress:(AddressModel*)model{
if(model ==nil) {
return; }
NSString*provinceid = model.provinceID;
NSString*cityid = model.cityID;
NSString*districtid = model.districtID;
__weak typeof(self) weakSelf = self;
/**查找省 下标*/
[self.dataArray enumerateObjectsUsingBlock:^(AddressJSONModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if([obj.iisEqualToString:provinceid]) {
weakSelf.provinceIndex= idx;
}
}];
/**查找市 下标*/
NSArray *cityModel = self.dataArray[_provinceIndex].s;
[cityModelenumerateObjectsUsingBlock:^(id _Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
AddressJSONModel *inmodel = (AddressJSONModel*)obj;
if([inmodel.iisEqualToString:cityid]) {
weakSelf.cityIndex= idx;
}
}];
/**查找区县 下标*/
AddressJSONModel*disModel = cityModel[_cityIndex];
[disModel.senumerateObjectsUsingBlock:^(AddressJSONModel*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
if([obj.iisEqualToString:districtid]) {
weakSelf.districtIndex= idx;
}
}];
[_dataPicker selectRow:_provinceIndex inComponent:0 animated:false];
[_dataPicker selectRow:_cityIndex inComponent:1 animated:false];
[_dataPicker selectRow:_districtIndex inComponent:2 animated:false];
[_dataPicker reloadAllComponents];
}
具体代码可以去github https://github.com/czlux/LFAddressChooseView
谢谢