一. 前言

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

  • 一般开发中,我们都写过 在自定义 view 中增加一个 model 的属性,外接直接传个 model 来,在 view 中 model 的 set 方法里对 view 的控件赋值的代码,例如在自定义 UITableViewCell 时用的很多,此时 view 是直接引用了 model

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

  • 本文简要介绍自己常用的两种写法来解耦 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 中

      #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; }

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

  • 说明

    • 将 view 中所有控件需要的数据依次列出
    • 定义一个 config 对象,使用链式编程的形式进行获取 view 需要的各种数据,在 config 中弱引用 view,把各种数据在赋值给 view
    • view 中需要定义一个配置数据的方法,方法的参数是个 block,block 传一个 config 对象给外界使用
    • view 和 config 为一整体,并不引用 model,因此脱离的 model 的限制,具有重用性
  • 示例
    • 如一个简单的展示标题、内容,还有一个按钮的 view
      #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.h
      #import <Foundation/Foundation.h>
      
      @class LXIntroduceView;
      
      @interface LXIntroduceViewConfig : NSObject
      
      - (instancetype)initWithIntroduceView:(LXIntroduceView *)introduceView;
      // 设置标题
      - (LXIntroduceViewConfig *(^)(NSString *))setupTitle;
      // 设置要显示的内容
      - (LXIntroduceViewConfig *(^)(NSString *))setupContent;
      // 设置按钮的标题
      - (LXIntroduceViewConfig *(^)(NSString *))setupBtnTitle; @end
    • LXIntroduceViewConfig.m
      @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");
      }];

四. 结尾

  • 一点一滴,仅此记录。

小记:iOS 中一般对于 view 不依赖 model 的的两种代码书写形式的更多相关文章

  1. vs中发布WebSever时启用HTTP-POST和HTTP-GET这两种协议

    一.问题介绍 在vs中建立一个websever项目时候默认是禁用HTTP-POST和HTTP-GET这两种协议的.但是如果你是在本机上去调试或者是在iis中浏览都会有HTTP-POST这种方式,因为这 ...

  2. Android代码中设置字体大小,字体颜色,显示两种颜色.倒计时效果

    Android代码中设置字体大小,字体颜色,显示两种颜色 在xml文件中字体大小用的像素 <TextView android:id="@+id/uppaid_time" an ...

  3. 【Java面试真题】剑指Offer53.2——0~n-1中缺失的数字(异或、二分两种解法)

    [Java实现]剑指Offer53.2--0~n-1中缺失的数字:面试真题,两种思路分享 前面有另一道面试题[Java实现]剑指offer53.1--在排序数组中查找数字(LeetCode34:在排序 ...

  4. WebGIS中解决使用Lucene进行兴趣点搜索排序的两种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 目前跟信息采集相关的一个项目提出了这样的一个需求:中国银行等 ...

  5. 关于实现自定义Dialog和实现Dialog里view的事件监听的两种方法

    一.自定义dialog. 二.实现dialog里view的事件监听 1.自定义dialog比较简单.在实例化new的时候,加入样式,布局就行了.或者重写dialog. 2.实现dialog里view的 ...

  6. 用Java集合中的Collections.sort方法对list排序的两种方法

    用Collections.sort方法对list排序有两种方法第一种是list中的对象实现Comparable接口,如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...

  7. 【转】java中byte数组与int类型的转换(两种方式)----不错

    原文网址:http://blog.csdn.net/piaojun_pj/article/details/5903009 java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法, ...

  8. springMVC中对HTTP请求form data和request payload两种数据发送块的后台接收方式

    最近在做项目中发现,前台提交数据时,如果通过form表单提交和ajax发送json时,springMVC后台接收不能都通过@ModelAttribute方式处理,经过一番查找后,ajax发送json请 ...

  9. iOS同一项目多个Target的快速实现方法 - 两种使用场景详解

    我们项目中,默认建好是只有一个target的,但是,一些场景中,多target能帮助我们更好的使用项目. 场景1: 同一项目,一般会分不同环境:开发环境.测试环境.正式(生产)环境. 这就涉及到一个请 ...

随机推荐

  1. 【MYSQL】删除数据后自动增长列归0的问题

    在清空数据表后发现自动增长id列在新增数据后仍然会按照之前的顺序生成 强迫症,就是想清空数据后让id从0开始,于是百度 执行以下sql语句可以让自动增长列归0 truncate table 表名 这是 ...

  2. Jmeter-返回值乱码处理

    Jmeter安装目录/bin/jmeter.properties中sampleresult.default.encoding默认为ISO-8859-1,将参数修改为 sampleresult.defa ...

  3. 2、kubeadm快速部署kubernetes(v1.15.0)集群190623

    一.网络规划 节点网络:192.168.100.0/24 Service网络:10.96.0.0/12 Pod网络(默认):10.244.0.0/16 二.组件分布及节点规划 master(192.1 ...

  4. 基础篇:MySQL系列之三

    一.MySQL简介 ​ MySQL原本是一个开放源代码的关系数据库管理系统,原开发者为瑞典的MySQL AB公司,该公司于2008年被Sun公司收购.2009年,Oracle收购sun公司,MySQL ...

  5. Ubuntu下rsyslog审计用户bash操作命令、收集、写入MySQL

    服务端 2台服务端:10.25.109.64.10.45.18.133 1.rsyslog最新版本安装 sudo add-apt-repository ppa:adiscon/v8-stable su ...

  6. 华东交通大学2017年ACM“双基”程序设计竞赛 1002

    Problem Description 一天YZW参加了学校组织交际舞活动,活动的开始活动方分别给男生和女生从1-n进行编号,按照从小到大顺时针的方式进行男女搭档分配,相同编号的男女组合成一对,例如一 ...

  7. python 用turtle 画小猪佩奇

    from turtle import * def nose(x,y):#鼻子 penup()#提起笔 goto(x,y)#定位 pendown()#落笔,开始画 setheading(-30)#将乌龟 ...

  8. (转)rename命令详解

    rename命令详解: 原文:http://www.cnblogs.com/amosli/p/3491649.html 对文件重命名是常用的操作之一,一般对单个文件的重命名用mv命令,如: amosl ...

  9. Spring Cloud下使用Feign Form实现微服务之间的文件上传

    背景 ​ Spring Cloud现在已经被越来越多的公司采用了,微服务架构比传统意义上的单服务架构从复杂度上多了很多,出现了很多复杂的场景.比如,我们的产品是个app,支持第三方登录功能,在手机端调 ...

  10. 再谈Drupal 7.X的性能优化运行速度问题

    D6升级D7之后,性能着实让人头大,不妨参考下面文章,另外站内搜索DOOOOR里其他优化文章,中西医结合吧.其中CDN和BOOST效果还可以,其他的没试过. 1,服务器 Web服务器建议,推荐使用HA ...