iOS进阶之架构设计MVVM的实现示例(5)

MVVM的核心在于:(个人意见) 1.MVVM的双向绑定; 2.Model与View解耦;

选用RAC实现MVVM架构,不是必要的,重要的实现架构,也可以自己用KVO实现,这里推荐使用Facebook开源的KVOController 框架。

一.MVVM架构

在这里插入图片描述

ZBMVVMSimpleViewController

协调viewModel绑定model,view绑定viewModel;

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //初始化
    self.simpleModel.name = @"帅斌";
    
    //创建视图
    [self.view addSubview:self.simpleView];
    
    /*绑定关系*/
    //viewModel绑定model
    [self.simpleViewModel bindModel:self.simpleModel];
    //view绑定viewModel
    [self.simpleView bindViewModel:self.simpleViewModel];

}

ZBMVVMSimpleView

创建视图,实现绑定viewModel的内部逻辑;

- (instancetype)init
{
    self = [super init];
    if(self){
        self.frame = [UIScreen mainScreen].bounds;
        self.backgroundColor = [UIColor whiteColor];
        
        self.nameButton = [UIButton buttonWithType:UIButtonTypeSystem];
        _nameButton.frame = CGRectMake(0, 0, 100, 50);
        _nameButton.center = CGPointMake(self.frame.size.width / 2.0, (self.frame.size.height / 3.0 * 1));
        _nameButton.backgroundColor = [UIColor blackColor];
        [_nameButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [_nameButton addTarget:self action:@selector(nameButtonAction) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_nameButton];
    }
    return self;
}
//按钮点击方法
- (void)nameButtonAction
{
    if(self.viewModel){
        [self.viewModel changeButtonTextAction];
    }
}
//绑定viewModel
- (void)bindViewModel:(id)viewModel
{
    self.viewModel = viewModel;
    @weakify(self);
    [[RACObserve(self.viewModel, nameStr) ignore:nil] subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        [self.nameButton setTitle:x forState:UIControlStateNormal];
    }];
}


ZBMVVMSimpleViewModel

ZBMVVMSimpleViewModel.h部分: 对外暴露的一些可供调用的接口:

@interface ZBMVVMSimpleViewModel : NSObject

@property (nonatomic, strong) NSString *nameStr;

//绑定model
- (void)bindModel:(id)model;

//按钮点击方法的实现
- (void)changeButtonTextAction;

@end

ZBMVVMSimpleViewModel.m部分: 实现绑定model,按钮更换name;

@interface ZBMVVMSimpleViewModel()

@property (nonatomic, strong) ZBMVVMSimpleModel *model;
@property (nonatomic, assign) BOOL              isClick;

@end
@implementation ZBMVVMSimpleViewModel

//绑定model
- (void)bindModel:(id)model
{
    self.model = model;
    self.nameStr = self.model.name;
}

//按钮点击方法的实现
- (void)changeButtonTextAction
{
    _isClick = !_isClick;
    if(_isClick){
       self.model.name = @"火之玉";
    }else{
       self.model.name = @"帅斌";
    }
    self.nameStr = self.model.name;
}

@end

通过这个简单的案例,可以看出MVVM各个部分之间的关系以及如何实现这一架构;
MVVM的Model和View没有交互,交互移步到ViewModel;View持有ViewModel,ViewModel持有Model。

二.工程实践

参照iOS MVVM+RAC 从框架到实战自己实现了个小demo:
在这里插入图片描述
这里原本想抽出tableView的dataSource父类,但看到网上一个比较好的案例,基于MVVM,用于快速搭建设置页,个人信息页的框架,也挺有意思的,学习了。

demo包涵MVVM框架、实战

如何用 ReactiveCocoa 将 view-model 与视图控制器连接起来

//
// View Controller
//
 
- (void) viewDidLoad {
    [super viewDidLoad];
 
    RAC(self.viewModel,  username) = [myTextfield rac_textSignal];
 
    RACSignal *usernameIsValidSignal = RACObserve(self.viewModel,  usernameValid);
 
    RAC(self.goButton,  alpha) = [usernameIsValidSignal
        map:  ^(NSNumber *valid) {
            return valid.boolValue ? @1 :  @0.5;
        }];
 
    RAC(self.goButton,  enabled) = usernameIsValidSignal;
 
    RAC(self.avatarImageView,  image) = RACObserve(self.viewModel,  userAvatarImage);
    
    RAC(self.userNameLabel,  text) = RACObserve(self.viewModel,  userFullName);
 
    @weakify(self);
    [[[RACSignal merge: @[RACObserve(self.viewModel,  tweets), 
                        RACObserve(self.viewModel,  allTweetsLoaded)]]
        bufferWithTime: 0 onScheduler: [RACScheduler mainThreadScheduler]]
        subscribeNext: ^(id value) {
            @strongify(self);
            [self.tableView reloadData];
        }];
    
    [[self.goButton rac_signalForControlEvents: UIControlEventTouchUpInside]
        subscribeNext:  ^(id value) {
            @strongify(self);
            [self.viewModel getTweetsForCurrentUsername];
        }];
}
 
-(UITableViewCell*)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
    // if table section is the tweets section
    if (indexPath.section == 0) {
        MYTwitterUserCell *cell = [self.tableView dequeueReusableCellWithIdentifier: @"MYTwitterUserCell" forIndexPath: indexPath];
        
        // grab the cell view model from the vc view model and assign it
        cell.viewModel = self.viewModel.tweets[indexPath.row];
        return cell;
    } else {
        // else if the section is our loading cell
        MYLoadingCell *cell = [self.tableView dequeueReusableCellWithIdentifier: @"MYLoadingCell" forIndexPath: indexPath];
        [self.viewModel loadMoreTweets];
        return cell;
    }
}
 
 
//
// MYTwitterUserCell
//
 
// this could also be in cell init
- (void) awakeFromNib {
    [super awakeFromNib];
    
    RAC(self.avatarImageView, image) = RACObserve(self,  viewModel.tweetAuthorAvatarImage);
    RAC(self.userNameLabel, text) = RACObserve(self,  viewModel.tweetAuthorFullName);
    RAC(self.tweetTextLabel, text) = RACObserve(self,  viewModel.tweetContent);
}


转载

iOS架构由浅入深 | MVVM

发布了249 篇原创文章 · 获赞 224 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/shifang07/article/details/99693371