针对MVC和MVVM这两种构建模式,网上随便一百度就是一大堆针对这两种构建模式的解说,总结起来无非以下两点:
- MVC(Model View Controller)是一种成熟的,苹果推荐的一个用来组织代码的权威范式,日常用的最多的一种构建模式,缺点就是viewController里面代码量厚重,耦合性强;
- MVVM(Model View View-Mode)是MVC衍生出来一种维护性较强、耦合性低的新的架构,它正式规范了视图和控制器紧耦合的性质,并引入新的组件,分离了视图(View)和模型(Model), 用户输入验证逻辑,视图显示逻辑,发起网络请求等代码的都放在viewModel中处理,从而大大的减少了viewController的代码量。
如果想深入了解他们的区别,就请移步自行Google吧,这里就不赘述了。对于这些东西,只有自己写过了,才能慢慢的从中体会到他们的差别,至于哪个好哪个适合自己,就只能自己从中取舍了。
下面讲述的是一个结合了三方ReactiveObjC
,采用MVVM的构建模式结合RAC写了一个登录的小功能,从demo中,能够很清楚的看到,viewController中的代码量大大的减少了,至少达到了V瘦身的效果😀。
首先要pod ReactiveObjC到项目当中
先来看view,里面处理简单的页面布局和一些判断
DCLoginView.h
@property (strong, nonatomic)UITextField *usernameTextField;//用户名
@property (strong, nonatomic)UITextField *passwordTxtField;、、密码
@property (strong, nonatomic)UIButton *signInButton;//登陆按钮
@property (strong, nonatomic)UIButton *signUpButton;//注册按钮
@property(nonatomic,assign)BOOL isValidate;//判断用户名和密码是否为空
DCLoginView.m
-(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setUpLoginView];
}
return self;
}
-(void)setUpLoginView
{
//用户名
_usernameTextField = [[UITextField alloc]init];
_usernameTextField.placeholder = @"用户名";
_usernameTextField.textColor = [UIColor blackColor];
_usernameTextField.font = [UIFont systemFontOfSize:15];
_usernameTextField.backgroundColor = [UIColor lightGrayColor];
_usernameTextField.layer.borderColor = [UIColor lightGrayColor].CGColor;
_usernameTextField.layer.borderWidth = 0.6;
_usernameTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[self addSubview:_usernameTextField];
//密码
_passwordTxtField = [[UITextField alloc]init];
_passwordTxtField.placeholder = @"密码";
_passwordTxtField.textColor = [UIColor blackColor];
_passwordTxtField.font = [UIFont systemFontOfSize:15];
_passwordTxtField.secureTextEntry = YES;
_passwordTxtField.backgroundColor = [UIColor lightGrayColor];
_passwordTxtField.layer.borderColor = [UIColor lightGrayColor].CGColor;
_passwordTxtField.layer.borderWidth = 0.6;
_passwordTxtField.clearButtonMode = UITextFieldViewModeWhileEditing;
[self addSubview:_passwordTxtField];
//登陆
_signInButton = [UIButton buttonWithType:UIButtonTypeCustom];
_signInButton.layer.cornerRadius = 4;
_signInButton.layer.masksToBounds = YES;
[_signInButton setTitle:@"登录" forState:UIControlStateNormal];
[_signInButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_signInButton.backgroundColor = [UIColor redColor];
[self addSubview:_signInButton];
//登陆
_signUpButton = [UIButton buttonWithType:UIButtonTypeCustom];
_signUpButton.layer.cornerRadius = 4;
_signUpButton.layer.masksToBounds = YES;
[_signUpButton setTitle:@"注册" forState:UIControlStateNormal];
[_signUpButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_signUpButton.backgroundColor = [UIColor redColor];
[self addSubview:_signUpButton];
}
-(void)layoutSubviews
{
[super layoutSubviews];
_usernameTextField.frame = CGRectMake((self.width - 150)/2, 190, 150, 40);
_passwordTxtField.frame = CGRectMake((self.width - 150)/2, CGRectGetMaxY(_usernameTextField.frame)+10, 150, 40);
_signInButton.frame = CGRectMake((self.width - 180)/2, CGRectGetMaxY(_passwordTxtField.frame)+30, 80, 40);
_signUpButton.frame = CGRectMake(CGRectGetMaxX(_signInButton.frame)+20, _signInButton.y, _signInButton.width, _signInButton.height);
}
-(BOOL)isValidate
{
if ([_usernameTextField.text isEqualToString:@""]) {
return NO;
}
if ([_passwordTxtField.text isEqualToString:@""]) {
return NO;
}
return YES;
}
再来看viewModel,拿到view中的用户输入的用户名和密码,利用RAC发射信号,里面处理一些网络请求
DCLoginViewModel.h
#import <Foundation/Foundation.h>
#import <ReactiveObjC/ReactiveObjC.h>
#import "DCLoginView.h"
@interface DCLoginViewModel : NSObject
@property(nonatomic,strong)RACCommand * loginCommond;
@property (nonatomic,copy)NSString *username;
@property (nonatomic,copy)NSString *password;
@property (nonatomic,strong) DCLoginView *loginView;
@end
DCLoginViewModel.m
-(void)setLoginView:(DCLoginView *)loginView
{
_loginView = loginView;
RAC(self, username) = loginView.usernameTextField.rac_textSignal;
RAC(self, password) = loginView.passwordTxtField.rac_textSignal;
}
- (instancetype) init
{
if (self = [super init]) {
[self setup];
}
return self;
}
- (void) setup {
__weak typeof(self) weakself = self;
self.loginCommond = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
if (!weakself.loginView.isValidate) {
[[weakself getCurrentVC] showMessage:@"账户名或密码不能为空!" afterDelay:1.0];
[subscriber sendCompleted];
return nil;
}
//处理网络数据请求,请求成功之后跳转
if ([weakself.loginView.usernameTextField.text isEqualToString:@"123"]&&[weakself.loginView.passwordTxtField.text isEqualToString:@"123"]) {
[[weakself getCurrentVC] showMessage:@"验证成功之后跳转到首页" afterDelay:1.0 completion:^{
[[weakself getCurrentVC] presentViewController:[[HomeViewController alloc]init] animated:YES completion:nil];
}];
}else
{
[[weakself getCurrentVC] showMessage:@"账户名或密码错误!账户名:123 密码:123" afterDelay:2.0];
}
[subscriber sendCompleted];
return nil;
}];
}];
}
@end
最后就是viewController了,里面只处理接收viewModel发过来的信号,关联viewModel和View
ViewController.m
#import "ViewController.h"
#import "DCLoginView.h"
#import "DCLoginViewModel.h"
@interface ViewController ()
@property (nonatomic,strong) DCLoginView *loginView;
@property (nonatomic,strong) DCLoginViewModel *loginViewModel;
@end
@implementation ViewController
-(void)loadView
{
DCLoginView *loginView = [[DCLoginView alloc]init];
self.loginView = loginView;
self.view = loginView;
}
-(DCLoginViewModel *)loginViewModel
{
if (!_loginViewModel) {
_loginViewModel = [DCLoginViewModel new];
}
return _loginViewModel;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
self.loginViewModel.loginView = self.loginView;
[self addLoginViewAction];
}
-(void)addLoginViewAction{
#pragma mark - 登陆
__weak typeof(self) weakself = self;
[[self.loginView.signInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
[self.loginViewModel.loginCommond execute:nil];
NSLog(@"signInButtonDidClick");
}];
#pragma mark - 注册
[[self.loginView.signUpButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
[weakself showMessage:@"点击了注册按钮" afterDelay:1.0];
}];
}
@end
viewController里面50行代码不到就能搞定了一个登录页。
RACCommand
和RACSignal
这两个类里面还有很多个方法,至于具体怎么用可以直接百度Google。
demo传送门,如果觉得喜欢的话,请给个星支持一下哦😀😀