demo:https://download.csdn.net/download/u012881779/10696246
之前使用MVC模式开发,觉得还蛮好用就一直使用着。
最近接触MVVM比较频繁,发现相比于MVC它会将网络请求从控制器中分离出来,这样能有效的为ViewController瘦身。
今天有点时间,就调用高德地图获取地区的接口写了一个分层选择地区的demo。
结构:
Controller
#import "GADistrictsViewController.h"
#import "GADistrictsCell.h"
#import "GADistrictsModel.h"
#import "GADistrictsViewModel.h"
@interface GADistrictsViewController () <UITableViewDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSMutableArray *dataMArr;
@property (strong, nonatomic) GADistrictsViewModel *viewModel;
@end
@implementation GADistrictsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[_tableView setSeparatorStyle:NO];
_tableView.estimatedRowHeight = 100;
_tableView.rowHeight = UITableViewAutomaticDimension;
if (!_viewModel) {
_viewModel = [GADistrictsViewModel new];
}
@weakify(self)
NSMutableDictionary *exeDict = [NSMutableDictionary new];
[exeDict setObject:@"bf4783277065f752f68490c4bf2b79e0" forKey:@"key"];
[exeDict setObject:@"3" forKey:@"subdistrict"];
[[_viewModel.districtsCommand execute:exeDict] subscribeNext:^(id _Nullable result) {
//NSLog(@"%@",result);
GADistrictsModel *tempModel = (GADistrictsModel *)[((GAResultDataModel *)result).districts firstObject];
self_weak_.dataMArr = tempModel.districts;
[self_weak_.tableView reloadData];
} error:^(NSError * _Nullable error) {
}];
}
#pragma mark UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return _dataMArr.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
GADistrictsModel *sectionModel = [_dataMArr objectAtIndex:section];
if (_dataMArr.count > section) {
sectionModel = [_dataMArr objectAtIndex:section];
NSInteger newIndex = 0;
if (sectionModel.select) {
for (int i = 0 ; i < sectionModel.districts.count ; i ++) {
GADistrictsModel *iModel = [sectionModel.districts objectAtIndex:i];
newIndex = newIndex + 1;
if (iModel.select) {
for (int j = 0 ; j < iModel.districts.count ; j ++) {
//GADistrictsModel *jModel = [iModel.districts objectAtIndex:j];
newIndex = newIndex + 1;
}
}
}
return newIndex+1;
}
}
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
GADistrictsModel *sectionModel = [_dataMArr objectAtIndex:indexPath.section];
if (_dataMArr.count > indexPath.section) {
sectionModel = [_dataMArr objectAtIndex:indexPath.section];
}
GADistrictsModel *model;
if (sectionModel.select) {
if (indexPath.row == 0) {
model = sectionModel;
} else {
NSInteger newIndex = 0;
for (int i = 0 ; i < sectionModel.districts.count ; i ++) {
GADistrictsModel *iModel = [sectionModel.districts objectAtIndex:i];
newIndex = newIndex + 1;
if (indexPath.row == newIndex) {
model = iModel;
break;
}
if (iModel.select) {
for (int j = 0 ; j < iModel.districts.count ; j ++) {
GADistrictsModel *jModel = [iModel.districts objectAtIndex:j];
newIndex = newIndex + 1;
if (indexPath.row == newIndex) {
model = jModel;
break;
}
}
}
}
}
} else {
model = sectionModel;
}
if ([[model class] isSubclassOfClass:[GADistrictsModel class]]) {
GADistrictsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GADistrictsCell"];
if (!cell) {
cell = [[[NSBundle mainBundle] loadNibNamed:@"GADistrictsCell" owner:nil options:nil] objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell setBackgroundColor:[UIColor clearColor]];
}
cell.model = model;
[cell.nameBut setTitle:model.name forState:UIControlStateNormal];
cell.codeLab.text = [model.adcode stringValue];
if ([model.level isEqualToString:@"province"]) {
cell.nameBut.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
[cell.nameBut setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
cell.codeLab.textColor = [UIColor blueColor];
} else if ([model.level isEqualToString:@"city"]) {
cell.nameBut.contentEdgeInsets = UIEdgeInsetsMake(0, 32, 0, 0);
[cell.nameBut setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
cell.codeLab.textColor = [UIColor blackColor];
} else if ([model.level isEqualToString:@"district"] || [model.level isEqualToString:@"street"]) {
cell.nameBut.contentEdgeInsets = UIEdgeInsetsMake(0, 64, 0, 0);
[cell.nameBut setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
cell.codeLab.textColor = [UIColor lightGrayColor];
}
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:0 reuseIdentifier:@"UITableViewCell"];
}
return cell;
}
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
GADistrictsCell *cell = [tableView cellForRowAtIndexPath:indexPath];
GADistrictsModel *model = cell.model;
if (model) {
model.select = !model.select;
[_tableView reloadData];
}
}
@end
Cell
#import <UIKit/UIKit.h>
#import "GADistrictsModel.h"
@interface GADistrictsCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UIButton *nameBut;
@property (weak, nonatomic) IBOutlet UILabel *codeLab;
@property (weak, nonatomic) GADistrictsModel *model;
@end
Model
#import "JSONModel.h"
/**
@protocol GADistrictsModel这个协议是必须要添加的,而且要加在@interface GAResultDataModel之前。
不然在GAResultDataModel中初始化districts字段时,系统就会要求这样写“NSArray <GADistrictsModel *> *districts”。
这种写法存在问题,它并不会将数组中的NSDictionary初始化为GADistrictsModel。
*/
@protocol GADistrictsModel
@end
@interface GAResultDataModel : JSONModel
@property (strong, nonatomic) NSNumber *newcount;
@property (assign, nonatomic) BOOL info;
@property (assign, nonatomic) NSInteger infocode;
@property (strong, nonatomic) NSString *status;
// "Optional"可选属性 (就是说这个属性可以为null或者为空)
@property (strong, nonatomic) NSDictionary <Optional> *suggestion;
@property (strong, nonatomic) NSArray <GADistrictsModel> *districts;
@end
@interface GADistrictsModel : JSONModel
@property (strong, nonatomic) NSNumber *adcode;
@property (strong, nonatomic) NSString *center;
@property (strong, nonatomic) NSString *level;
@property (strong, nonatomic) NSString *name;
// "Ignore"忽略属性 (就是完全忽略这个属性)。应为在国家那一级这个字段返回的数组类型,在城市那一级这个字段返回的字符串类型。如果不能忽略就需要再单独创建一个model。
@property (strong, nonatomic) NSString <Ignore> *citycode;
@property (strong, nonatomic) NSArray <GADistrictsModel>*districts;
@property (assign, nonatomic) BOOL select;
@end
#import "GADistrictsModel.h"
@implementation GAResultDataModel
// 设置所有的属性为可选(所有属性值可以为空)
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
return YES;
}
// key映射
+ (JSONKeyMapper *)keyMapper {
return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{@"newcount": @"count" }];
}
@end
@implementation GADistrictsModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
return YES;
}
@end
ViewModel
#import <Foundation/Foundation.h>
#import "ReactiveObjC.h"
@interface GADistrictsViewModel : NSObject
// 获取地区
@property (nonatomic,strong) RACCommand *districtsCommand;
@end
#import "GADistrictsViewModel.h"
#import "GADistrictsAPI.h"
#import "GADistrictsModel.h"
@implementation GADistrictsViewModel
- (RACCommand *)districtsCommand {
if (!_districtsCommand) {
_districtsCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[GADistrictsAPI aMapDistrictsWithParameters:input Success:^(id result) {
GAResultDataModel *tempResultModel = [[GAResultDataModel alloc] initWithDictionary:result error:nil];
// 发送信号
[subscriber sendNext:tempResultModel];
[subscriber sendCompleted];
} failed:^(NSError *error) {
[subscriber sendError:error];
}];
return nil;
}];
}];
}
return _districtsCommand;
}
@end
API
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
typedef void (^SuccessBlock)(id result);
typedef void (^FailedBlock)(NSError *error);
@interface GADistrictsAPI : NSObject
/// 高德地图-获取省市县
+ (void)aMapDistrictsWithParameters:(NSDictionary *)parameter Success:(SuccessBlock)success failed:(FailedBlock)failed;
@end
#import "GADistrictsAPI.h"
@implementation GADistrictsAPI
+ (void)aMapDistrictsWithParameters:(NSDictionary *)parameter Success:(SuccessBlock)success failed:(FailedBlock)failed {
NSString *tempUrl = [NSString stringWithFormat:@"https://restapi.amap.com/v3/config/district?key=%@&subdistrict=%@",[parameter objectForKey:@"key"],[parameter objectForKey:@"subdistrict"]];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:tempUrl parameters:[NSMutableDictionary dictionary] progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failed(error);
}];
}
@end
示意图: