小记:iOS 中通常对于 view 不依赖 model 的的两种代码书写形式

一. 前言

  • 对于在 MVC 的定义中,view 层是不引用 model 层,view 和 model 是不相往来的编程

  • 通常开发中,咱们都写过 在自定义 view 中增长一个 model 的属性,外接直接传个 model 来,在 view 中 model 的 set 方法里对 view 的控件赋值的代码,例如在自定义 UITableViewCell 时用的不少,此时 view 是直接引用了 modelatom

  • 基于封装的思想,咱们须要竟可能的复用咱们的代码,复用咱们的 view,这时咱们须要进行解耦,不依赖于某个特殊的 model。另外,若是对于很特殊的 view,整个项目中没有什么重用的,能够按以前状况处理code

  • 本文简要介绍本身经常使用的两种写法来解耦 view 和 model,使之更符合 MVC 的定义对象

二.定义 ViewModel 对象及 ViewModelType (协议) 的形式

  • 说明
    • 将 view 中全部控件须要的数据依次列出
    • 定义 ViewModelType 一种协议,定义协议方法 ,旨在经过协议方法,返回 view 须要的数据
    • view 中控件赋值,须要外接传入遵照 ViewModelType 协议的 ViewModel,在 ViewModel 的 set 方法里进行控件赋值
    • 该 ViewModel 的建立是依赖具体的 model 的,须要遵照 ViewModelType 协议
    • view 和 ViewModelType 为一总体,经过更换不一样的 ViewModel 来达到重用。更换不一样 ViewModel,也至关于更换了数据 model。
  • 示例
    • 如一个 cell (有大标题,几个子标题和标题对应的内容,状态,图片等)图片

      @interface LXReservationCell : UITableViewCell
      
      @property (nonatomic, weak) id<LXReservationCellViewModelType> viewModel;
      
      @end
    • LXReservationCellViewModelType 协议开发

      @protocol LXReservationCellViewModelType <NSObject>
      
      // 标题
      @property (nonatomic, copy, readonly) NSString *title;
      // 第一个子标题
      @property (nonatomic, copy, readonly) NSString *firstItemTitle;
      // 第一个子标题对应的内容
      @property (nonatomic, copy, readonly) NSString *firstItemContent;
      
      @end
    • LXReservationCellViewModel 中it

      #import <Foundation/Foundation.h>
      
      @class LXReservationItem;
      
      @interface LXReservationCellViewModel : NSObject
      
      - (instancetype)initWithItem:(LXReservationItem *)item;
      
      @end
      @interface LXReservationCellViewModel () <LXReservationCellViewModelType>
      // 标题
      @property (nonatomic, copy) NSString *title;
      // 第一个子标题
      @property (nonatomic, copy) NSString *firstItemTitle;
      // 第一个子标题对应的内容
      @property (nonatomic, copy) NSString *firstItemContent;
      @end
      @implementation LXReservationCellViewModel
      
      - (instancetype)initWithItem:(LXReservationItem *)item {
          if (self = [super init]) {
              self.title = item.title;
              self.firstItemTitle = item.orderCategory;
              self.firstItemContent = item.orderdate;
      
          }
          return self;
      
      }

3、定义 view 对应的 config,使用链式编程的形式进行对 view 控件赋值

  • 说明
    • 将 view 中全部控件须要的数据依次列出
    • 定义一个 config 对象,使用链式编程的形式进行获取 view 须要的各类数据,在 config 中弱引用 view,把各类数据在赋值给 view
    • view 中须要定义一个配置数据的方法,方法的参数是个 block,block 传一个 config 对象给外界使用
    • view 和 config 为一总体,并不引用 model,所以脱离的 model 的限制,具备重用性
  • 示例
    • 如一个简单的展现标题、内容,还有一个按钮的 viewio

      #import <UIKit/UIKit.h>
      
      @class LXIntroduceViewConfig;
      
      @interface LXIntroduceView : UIView
      // 标题
      @property (nonatomic, copy) NSString *title;
      // 内容
      @property (nonatomic, copy) NSString *content;
      // 按钮标题
      @property (nonatomic, copy) NSString *btnTitle;
      
      // 配置 view 对应的数据的方法
      - (void)lx_makeWithConfig:(void(^)(LXIntroduceViewConfig *config))block;
      - (void)lx_makeWithConfig:(void (^)(LXIntroduceViewConfig *))block {
        LXIntroduceViewConfig *config = [[LXIntroduceViewConfig alloc]initWithIntroduceView:self];
        !block? :  block(config);
      }
    • LXIntroduceViewConfig.hclass

      #import <Foundation/Foundation.h>
      
      @class LXIntroduceView;
      
      @interface LXIntroduceViewConfig : NSObject
      
      - (instancetype)initWithIntroduceView:(LXIntroduceView *)introduceView;
      // 设置标题
      - (LXIntroduceViewConfig *(^)(NSString *))setupTitle;
      // 设置要显示的内容
      - (LXIntroduceViewConfig *(^)(NSString *))setupContent;
      // 设置按钮的标题
      - (LXIntroduceViewConfig *(^)(NSString *))setupBtnTitle;
      
      @end
    • LXIntroduceViewConfig.mtest

      @interface LXIntroduceViewConfig ()
      // 弱引用 view 
      @property (nonatomic, weak) LXIntroduceView *introduceView;
      @end
      
      @implementation LXIntroduceViewConfig
      // init
      - (instancetype)initWithIntroduceView:(LXIntroduceView *)introduceView {
          if (self = [super init]) {
              self.introduceView = introduceView;
          }
          return self;    
      }
      // 把标题传给 view,view 中 set 方法接收
      - (LXIntroduceViewConfig *(^)(NSString *))setupTitle {
          return ^(NSString *tmp) {
              self.introduceView.title = tmp;
              return self;
          };
      }
      // 把内容传给 view,view 中 set 方法接收
      - (LXIntroduceViewConfig *(^)(NSString *))setupContent {
          return ^(NSString *tmp) {
              self.introduceView.content = tmp;
              return self;
          };
      }
      // 把按钮标题传给 view
      - (LXIntroduceViewConfig *(^)(NSString *))setupBtnTitle {
          return ^(NSString *tmp) {
              self.introduceView.btnTitle = tmp;
              return self;
          };
      }
      @end
    • 外界使用

      LXIntroduceView *introduceView = [[LXIntroduceView alloc]init];
      [introduceView lx_makeWithConfig:^(LXIntroduceViewConfig *config) {
          config
          .setupTitle(self.resultItem.title)
          .setupContent(self.resultItem.content) 
          .setupBtnTitle(@"test");
      }];

四. 结尾

  • 一点一滴,仅此记录。
相关文章
相关标签/搜索