1. 程式人生 > >iOS底層原理之架構設計

iOS底層原理之架構設計

何為架構?

  • 架構(Architecture):軟體開發中的設計方案,類與類之間的關係、模組與模組之間的關係、客戶端與服務端的關係。
  • 經常聽到的架構名詞:MVC、MVP、MVVM、VIPER、CDD、三層架構、四層架構等。

MVC - Apple版

Model-View-Controller
MVC - Apple版
是iOS開發中常用的模式 ,Model和View之間沒有任何直接到關係,通過Controller作為橋樑將二者聯絡起來。(Controller可初始化資料並將資料傳遞給Model;Model可以將資料傳遞給Controller,Controller將這些資料賦給View展示;View可以傳遞事件給Controller,Controller通過事件判斷區出來資料Model)。
優點

:View、Model可以重複利用,可以獨立使用
缺點:Controller的程式碼過於臃腫。

MVC – 變種

Model-View-Controller
 MVC – 變種
變種的MVC,每一個view對應一個Model,只要Controller設定View的Model,就可直接展示對應的示圖(常見的cell新增一個model屬性就是這種模式)。
優點:對Controller進行瘦身,將View內部的細節封裝起來了,外界不知道View內部的具體實現;
缺點:View依賴於Model。

MVP

  • Model-View-Presenter
    MVP
  • MVP中的V在iOS中指的是ViewController和View。MVP將MVC的ViewController進行拆分:檢視資料邏輯處理部分為P,ViewController剩餘部分與View合併成V,V和P之間通過Protocol進行通訊。
  • MVP實現了各模組的解藕,具有更好的可測試性。但是總體程式碼量比MVC大。
    另外,iOS MVC更適用於快速開發,即程式碼規模較小的專案。因此將簡單的MVC的Demo改成MVP,反而會顯得笨拙。
#import "MJAppPresenter.h"
#import "MJApp.h"//Model
#import "MJAppView.h"//View
@interface MJAppPresenter() <MJAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@end
@implementation MJAppPresenter
- (instancetype)initWithController:(UIViewController *)controller
{
    if (self = [super init]) {
        self.controller = controller;
        // 建立View
        MJAppView *appView = [[MJAppView alloc] init];
        appView.frame = CGRectMake(100, 100, 100, 150);
        appView.delegate = self;
        [controller.view addSubview:appView];
        
        // 載入模型資料
        MJApp *app = [[MJApp alloc] init];
        app.name = @"QQ";
        app.image = @"QQ";
        
        // 賦值資料
        [appView setName:app.name andImage:app.image];
    }
    return self;
}
#pragma mark - MJAppViewDelegate
- (void)appViewDidClick:(MJAppView *)appView
{
    NSLog(@"presenter 監聽了 appView 的點選");
}
@end

#import "ViewController.h"
#import "MJAppPresenter.h"
@interface ViewController ()
@property (strong, nonatomic) MJAppPresenter *presenter;
//@property (strong, nonatomic) MJOtherPresenter *presenter1;
//@property (strong, nonatomic) MJNewsPresenter *presenter2;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.presenter = [[MJAppPresenter alloc] initWithController:self];
}

可以看出View和Model的都是直接和Presenter傳遞值和互動的,時間處理也在Presenter中,不同的View和Model可以給Controller新增不同的Presenter屬性即可,Controller不再直接是View和Model的橋樑。

MVVM

  • Model-View-ViewModel
    MVVM
  • MVVM 模式將 Presenter 改名為 ViewModel,基本上與 MVP 模式完全一致。 唯一的區別是,它採用雙向繫結(data-binding);當被繫結物件某個值的變化時,繫結物件會自動感知,無需被繫結物件主動通知繫結物件。可以使用KVO和RAC實現。例如在Label中顯示倒計時,是V綁定了包含定時器的VM。
  • 雙向繫結在MVVM中指的是V和VM之間相互繫結。例如TextField的text長度達到閾值,另一個Button改變背景顏色。這個過程中首先VM感知V中TextField的text屬性長度變化,V感知VM中對應的狀態屬性。一旦V中TextField的text屬性長度超出VM中的閾值,VM中的狀態屬性改變,觸發V中Button的背景色發生改變。
  • MVVM的優點:
  1. 低耦合。檢視(View)可以獨立於Model變化和修改,一個ViewModel可以繫結到不同的"View"上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
  2. 可重用性。你可以把一些檢視邏輯放在一個ViewModel裡面,讓很多view重用這段檢視邏輯。
  3. 獨立開發。開發人員可以專注於業務邏輯和資料的開發(ViewModel),設計人員可以專注於頁面設計。
  4. 可測試。介面素來是比較難於測試的,而現在測試可以針對ViewModel來寫。
  • facebookKVOController九可以用來雙向繫結,其github地址為:KVOController
//View
#import <UIKit/UIKit.h>
@class MJAppView, MJAppViewModel;
@protocol MJAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(MJAppView *)appView;
@end
@interface MJAppView : UIView
@property (weak, nonatomic) MJAppViewModel *viewModel;
@property (weak, nonatomic) id<MJAppViewDelegate> delegate;
@end

#import "MJAppView.h"
#import "NSObject+FBKVOController.h"
@interface MJAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end
@implementation MJAppView
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        UIImageView *iconView = [[UIImageView alloc] init];
        iconView.frame = CGRectMake(0, 0, 100, 100);
        [self addSubview:iconView];
        _iconView = iconView;
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.frame = CGRectMake(0, 100, 100, 30);
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        _nameLabel = nameLabel;
    }
    return self;
}
- (void)setViewModel:(MJAppViewModel *)viewModel
{
    _viewModel = viewModel;
    __weak typeof(self) waekSelf = self;
    //監聽viewModel的name和image屬性變化,一旦變化就給view賦值
    [self.KVOController observe:viewModel keyPath:@"name" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
        waekSelf.nameLabel.text = change[NSKeyValueChangeNewKey];
    }];
    [self.KVOController observe:viewModel keyPath:@"image" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
        waekSelf.iconView.image = [UIImage imageNamed:change[NSKeyValueChangeNewKey]];
    }];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {
        [self.delegate appViewDidClick:self];
    }
}
@end

//ViewModel
#import <UIKit/UIKit.h>
@interface MJAppViewModel : NSObject
- (instancetype)initWithController:(UIViewController *)controller;
@end
#import "MJAppViewModel.h"
#import "MJApp.h"
#import "MJAppView.h"
@interface MJAppViewModel() <MJAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *image;
@end
@implementation MJAppViewModel
- (instancetype)initWithController:(UIViewController *)controller
{
    if (self = [super init]) {
        self.controller = controller;
        // 建立View
        MJAppView *appView = [[MJAppView alloc] init];
        appView.frame = CGRectMake(100, 100, 100, 150);
        appView.delegate = self;
        appView.viewModel = self;//雙向繫結
        [controller.view addSubview:appView];
        // 載入模型資料
        MJApp *app = [[MJApp alloc] init];
        app.name = @"QQ";
        app.image = @"QQ";
        // 設定資料
        self.name = app.name;
        self.image = app.image;
    }
    return self;
}
#pragma mark - MJAppViewDelegate
- (void)appViewDidClick:(MJAppView *)appView
{
    NSLog(@"viewModel 監聽了 appView 的點選");
}
@end

//Controller
#import "ViewController.h"
#import "MJAppViewModel.h"
@interface ViewController ()
@property (strong, nonatomic) MJAppViewModel *viewModel;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.viewModel = [[MJAppViewModel alloc] initWithController:self];
}
@end

可以看出Controller 中只添加了ViewModel,不再與View和Model有任何關係,ViewModel初始化了View和Model,並將Model資料繫結給自己;而View綁定了ViewModel屬性,並監聽器值得變化,一旦有變化設定相應的控制元件;ViewModel為View代理,響應view的一些事件。

設計模式

  • 設計模式(Design Pattern)
    是一套被反覆使用、程式碼設計經驗的總結
    使用設計模式的好處是:可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性
    一般與程式語言無關,是一套比較成熟的程式設計思想
  • 設計模式可以分為三大類
  1. 建立型模式:物件例項化的模式,用於解耦物件的例項化過程
    單例模式、工廠方法模式,等等
  2. 結構型模式:把類或物件結合在一起形成一個更大的結構
    代理模式、介面卡模式、組合模式、裝飾模式,等等
  3. 行為型模式:類或物件之間如何互動,及劃分責任和演算法
    觀察者模式、命令模式、責任鏈模式,等等

面試題

  • 講講 MVC、MVVM、MVP,以及你在專案裡具體是怎麼寫的?
    把上面的講一下就好了。

  • 你自己用過哪些設計模式?
    單例、代理、觀察者模等等。

  • 一般開始做一個專案,你的架構是如何思考的?
    從實現方式思考,從結構模組思考,自己發揮。