[iOS]MVVM简单使用

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

示意图:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值