iOS架构师_架构模式(代理,block,通知,MVC,MVP,MVVM)

1.什么是架构?

没有明确的定义,属于设计的一方面,没明确的把设计和架构进行区分,它可以小到类与类之间的交互,大到不同模块之间,以及不同业务之间的交互,都可以从架构的层面去理解它。

所有架构和设计模式的目的都是为了解耦合

2.基本的架构基础

案例需求:女朋友让男朋友去做饭,完了以后给抱抱

GirlFriend类
.h

#import <Foundation/Foundation.h>

@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;

- (void)cookingIsDone;

- (void)begin;

@end

.m

#import "GirlFriend.h"
#import "BoyFriend.h"

@implementation GirlFriend
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)cookingIsDone {
    NSLog(@"给个爱的抱抱");
}

- (void)begin {
    [[BoyFriend sharedInstance] cooking];
}

@end

BoyFriend类

.h

#import <Foundation/Foundation.h>

@interface BoyFriend : NSObject

+ (instancetype)sharedInstance;

- (void)cooking;

@end

.m

#import "BoyFriend.h"
#import "GirlFriend.h"

@implementation BoyFriend

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)cooking {
    NSLog(@"baby,欧巴开始做饭了");
    [[GirlFriend sharedInstance] cookingIsDone];
}

@end

我们看上面的代码,可以看出,BoyFriend类和GirlFriend类是相互依赖的,那我们怎么解决这种依赖关系呢?三种方式代理和block以及通知

代理

BoyFriend.h

#import <Foundation/Foundation.h>

@protocol BoyFriendDelegate <NSObject>

- (void)boyFriendMakeCooking;

@end

@interface BoyFriend : NSObject

+ (instancetype)sharedInstance;

- (void)cooking;

@property (nonatomic, weak) id<BoyFriendDelegate> delegate;

@end

BoyFriend.m

#import "BoyFriend.h"
//#import "GirlFriend.h"

@implementation BoyFriend

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)cooking {
    NSLog(@"baby,欧巴开始做饭了");
//    [[GirlFriend sharedInstance] cookingIsDone];

    if (_delegate) {
        [_delegate boyFriendMakeCooking];
    }
}


@end

GirlFriend.h

#import <Foundation/Foundation.h>
#import "BoyFriend.h"

@interface GirlFriend : NSObject <BoyFriendDelegate>
+ (instancetype)sharedInstance;

- (void)cookingIsDone;

- (void)begin;

@end

GirlFriend.m

#import "GirlFriend.h"

@implementation GirlFriend
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)cookingIsDone {
    NSLog(@"给个爱的抱抱");
}

- (void)begin {
    [BoyFriend sharedInstance].delegate = self;

    [[BoyFriend sharedInstance] cooking];
}

- (void)boyFriendMakeCooking {
    NSLog(@"给个爱的抱抱");
}

@end

block

BoyFriend.h

#import <Foundation/Foundation.h>

@interface BoyFriend : NSObject

+ (instancetype)sharedInstance;

//- (void)cooking;

@property (nonatomic, copy) void(^myBolock)(NSString *);

- (void)cooking:(void(^)())success;

@end

BoyFriend.m

#import "BoyFriend.h"
//#import "GirlFriend.h"

@implementation BoyFriend

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

//- (void)cooking {
//    NSLog(@"baby,欧巴开始做饭了");
////    [[GirlFriend sharedInstance] cookingIsDone];
//    
////    if (_delegate) {
////        [_delegate boyFriendMakeCooking];
////    }
//}

- (void)cooking:(void (^)())success {
//    // 判断是否有这个block
//    if (self.myBolock) {
//        // 用参数的形式,把这信息,给block里面赋参数,传出去
//        self.myBolock(@"baby,欧巴开始做饭了");
//    }

    NSLog(@"baby,欧巴开始做饭了");
    // 调用这个block,把myBlock回调回去
    success(self.myBolock);
}

@end

GirlFriend.h

#import <Foundation/Foundation.h>
#import "BoyFriend.h"

@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;

- (void)cookingIsDone;

- (void)begin;

@end

GirlFriend.m

#import "GirlFriend.h"

@implementation GirlFriend
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)begin {
//    // 声明这个block, 其实这一步可以省去的
//    [BoyFriend sharedInstance].myBolock = ^(NSString *str) {
//        NSLog(@"%@",str);
//    };
//    
    // 调用这个方法,里面对block进行声明
    [[BoyFriend sharedInstance] cooking:^{
        NSLog(@"给个爱的抱抱");
    }];
}

@end

block和代理是类似的方式,但是我们发现GirlFriend类中仍然需要引入BoyFriend的头文件,有没有办法,完全解除两个类的关系呢?苹果后期给出的通知就可以解决我们的问题。

通知

Header.h

#ifndef Header_h
#define Header_h

static NSString * const Notif_Begin = @"Notif_Begin";
static NSString * const Notif_cookingIsDone = @"Notif_cookingIsDone";

//#define Notif_Begin @"Notif_Begin"
//#define Notif_cookingIsDone @"Notif_cookingIsDone"

#endif /* Header_h */

GirlFriend.h

#import <Foundation/Foundation.h>
#import "Header.h"

@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;

- (void)begin;

@end

GirlFriend.m

#import "GirlFriend.h"

@implementation GirlFriend
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cookingIsDone) name:Notif_cookingIsDone object:nil];
    }
    return self;
}
- (void)cookingIsDone {
    NSLog(@"给个爱的抱抱");
}

- (void)begin {
    [[NSNotificationCenter defaultCenter] postNotificationName:Notif_Begin object:nil];
}

@end

BoyFriend.h

#import <Foundation/Foundation.h>
#import "Header.h"

@interface BoyFriend : NSObject

+ (instancetype)sharedInstance;

- (void)addNotification;

@end

BoyFriend.m

#import "BoyFriend.h"

@implementation BoyFriend

+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)addNotification {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cooking) name:Notif_Begin object:nil];
}

- (void)cooking {
    NSLog(@"baby,欧巴开始做饭了");
    [[NSNotificationCenter defaultCenter] postNotificationName:Notif_cookingIsDone object:nil];
}
@end

3.MVC架构方式-面向对象

这里写图片描述

Model View Controller

Model

Paper.h

#import <Foundation/Foundation.h>

@interface Paper : NSObject
@property (nonatomic, strong) NSString *content;
@end

View

MVCView.h

#import <UIKit/UIKit.h>
#import "Paper.h"

@protocol MVCViewDelegate <NSObject>

- (void)onPrintBtnClick;

@end

@interface MVCView : UIView

- (void)printOnView:(Paper *)paper;

@property (nonatomic, weak) id<MVCViewDelegate> delegate;
@property (nonatomic, strong) UIButton *btnPrint;

@end

MVCView.m

#import "MVCView.h"

@implementation MVCView

- (void)printOnView:(Paper *)paper {
    NSLog(@"在MVCView中打印出的内容:%@",paper.content);
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.backgroundColor = [UIColor grayColor];

        self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50)];
        [self.btnPrint setTitle:@"print" forState:UIControlStateNormal];
        [self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.btnPrint];
    }
    return self;
}

- (void)onPrintClick {
//    NSLog(@"采集的事件");
    if (_delegate && [self.delegate respondsToSelector:@selector(onPrintBtnClick)]) {
        [_delegate onPrintBtnClick];
    }
}

@end

Controller
MVCViewController.h

#import <UIKit/UIKit.h>

@interface MVCViewController : UIViewController

@end

MVCViewController.m

#import "MVCViewController.h"
#import "MVCView.h"
#import "Paper.h"

@interface MVCViewController () <MVCViewDelegate>
@property (nonatomic, strong) MVCView *myView;
@property (nonatomic, strong) Paper *paper;

@end

@implementation MVCViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.myView = [MVCView new];
    self.myView.delegate = self;
    self.myView.frame = self.view.bounds;
    [self.view addSubview:self.myView];

    self.paper = [Paper new];
    self.paper.content = @"mvc内容模式";

    [self.myView printOnView:self.paper];

}

// 实现了代理方法
- (void)onPrintBtnClick {

    int rand = arc4random_uniform(10);
    _paper.content = [NSString stringWithFormat:@"改变的数据 %d",rand+1];

    [self.myView printOnView:self.paper];
}

@end

MVC架构方式其实就是把数据,视图,控制器三者分离,是最基础的设计模式,MVP和MVVM都是在其基础上衍生出来的。

4.MVP架构方式-面向接口

这里写图片描述
Model View Presenter

Controller中的所有逻辑都放在Presenter中实现,与MVC不同的是Model与View是没有任何联系的,都是通过Presenter来交互

代码示例:

这里写图片描述
注意:MVP的架构方式还是需要Controller的,它只不过是把Controller中的逻辑放在Presenter中去实现

Model

#import <Foundation/Foundation.h>

@interface MVPModel : NSObject
@property (nonatomic, strong) NSString *content;

@end

View

MVPView.h

#import <UIKit/UIKit.h>

@protocol MVPViewDelegate <NSObject>

- (void)viewShowBtnClick;

@end

@interface MVPView : UIView
@property (nonatomic, weak) id<MVPViewDelegate> delegate;

- (void)showView:(NSString *)content;
@end

MVPView.m

#import "MVPView.h"

@interface MVPView ()
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIButton *btnPrint;
@end

@implementation MVPView

- (instancetype)init
{
    self = [super init];
    if (self) {

        self.backgroundColor = [UIColor grayColor];
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 300, 30)];

        self.label.textAlignment = NSTextAlignmentCenter;

        self.label.textColor = [UIColor blackColor];

        [self addSubview:self.label];

        self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 50)];

        [self.btnPrint setTitle:@"来点我呀" forState:UIControlStateNormal];

        [self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];


        [self addSubview:self.btnPrint];

    }
    return self;
}

- (void)showView:(NSString *)content {
    self.label.text = content;
}

- (void)onPrintClick {
    if (_delegate && [_delegate respondsToSelector:@selector(viewShowBtnClick)]) {
        [_delegate viewShowBtnClick];
    }
}

创建继承自NSObject的类Presenter
Presenter.h

#import <Foundation/Foundation.h>
#import "MVPModel.h"
#import "MVPView.h"

@interface Presenter : NSObject <MVPViewDelegate>
@property (nonatomic, strong) MVPModel *model;
@property (nonatomic, strong) MVPView *view;

- (void)usageLogic;
@end

Presenter.m

#import "Presenter.h"

@implementation Presenter

- (void)usageLogic {
    NSString *contentStr = self.model.content;

    self.view.delegate = self;
    [self.view showView:contentStr];
}

- (void)viewShowBtnClick {
    int num = arc4random_uniform(20);
    self.model.content = [NSString stringWithFormat:@"mvp--%d-",num];

    [_view showView:_model.content];
}
@end

Controller
MVPViewController.m

#import "MVPViewController.h"
#import "Presenter.h"
#import "MVPModel.h"
#import "MVPView.h"

@interface MVPViewController () 
@property (nonatomic, strong) Presenter *presenter;
@property (nonatomic, strong) MVPView  *mvpView;
@property (nonatomic, strong) MVPModel *mvpModel;
@end

@implementation MVPViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    _presenter = [[Presenter alloc] init];

    _mvpView = [[MVPView alloc] init];
    _mvpView.frame = self.view.bounds;
    [self.view addSubview:_mvpView];

    _mvpModel = [MVPModel new];
    _mvpModel.content = @"MVP的模式";
    // model还没赋值
    _presenter.model = _mvpModel;
    _presenter.view = _mvpView;
    [_presenter usageLogic];

}

@end

5.MVVM架构方式-响应式编程

这里写图片描述

这里写图片描述

MVVMModel.h

#import <Foundation/Foundation.h>

@interface MVVMModel : NSObject
@property (nonatomic, copy) NSString *content;
@end

MVVMView.h


#import <UIKit/UIKit.h>
#import "MVVMViewModel.h"


@interface MVVMView : UIView
@property (nonatomic, strong) UILabel *labelContent;
@property (nonatomic, strong) UIButton *btnPrint;
@property (nonatomic, strong) MVVMViewModel *vm;

- (void)showView:(MVVMViewModel *)viewModel;

@end

MVVMView.m

#import "MVVMView.h"

@implementation MVVMView

- (instancetype)init
{
    self = [super init];
    if (self) {

        self.backgroundColor = [UIColor grayColor];
        self.labelContent = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 300, 30)];

        self.labelContent.textAlignment = NSTextAlignmentCenter;

        self.labelContent.textColor = [UIColor blackColor];

        [self addSubview:self.labelContent];

        self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 50)];

        [self.btnPrint setTitle:@"来点我呀---" forState:UIControlStateNormal];

        [self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];


        [self addSubview:self.btnPrint];

    }
    return self;
}

- (void)onPrintClick {
    [self.vm viewModelPrintClick];
}

- (void)showView:(MVVMViewModel *)viewModel {
    self.vm = viewModel;
    [self.KVOController observe:viewModel keyPath:@"contentStr" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
        _labelContent.text = change[NSKeyValueChangeNewKey];
    }];
}

@end

MVVMViewModel.h

#import <Foundation/Foundation.h>
#import "FBKVOController.h"
#import "NSObject+FBKVOController.h"
#import "MVVMModel.h"

@interface MVVMViewModel : NSObject

@property (nonatomic, copy) NSString *contentStr;

- (void)setWithModel:(MVVMModel *)model;

- (void)viewModelPrintClick;
@end

MVVMViewModel.m

#import "MVVMViewModel.h"

@interface MVVMViewModel ()
@property (nonatomic, strong) MVVMModel *model;
@end

@implementation MVVMViewModel
- (void)setWithModel:(MVVMModel *)model {
    self.model = model;
    self.contentStr = self.model.content;
}

- (void)viewModelPrintClick {
    self.model.content = @"MVVMModel";

    int num = arc4random_uniform(20);
    self.model.content = [NSString stringWithFormat:@"%d",num];
    self.contentStr = self.model.content;
}

@end

MVVMController.m

#import "MVVMController.h"
#import "MVVMModel.h"
#import "MVVMView.h"
#import "MVVMViewModel.h"

@interface MVVMController ()
@property (nonatomic, strong) MVVMView *mvvmView;
@property (nonatomic, strong) MVVMModel *model;
@property (nonatomic, strong) MVVMViewModel *viewModel;
@end

@implementation MVVMController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.model = [[MVVMModel alloc] init];
    self.model.content = @"MVVM架构模式";

    _viewModel = [MVVMViewModel new];

    _mvvmView = [MVVMView new];
    _mvvmView.frame = self.view.bounds;
    [self.view addSubview:_mvvmView];

    [_viewModel setWithModel:_model];
    [_mvvmView showView:_viewModel];

}

@end

这里写图片描述

注意:FBKVOController是个使用KVO的小框架,可以去gitHub上去找。我们在这使用KVO的模式来使ViewModel和View进行数据交互。

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/80497961