iOS 架构组件:让你的 TableView 优雅起来

2023-11-20

640?wx_fmt=gif

640?wx_fmt=jpeg

看什么看!点我呀! 全栈程序员,免费入门到精通! 640?wx_fmt=jpeg


作者丨indulge_in
https://www.jianshu.com/p/7db73489ad99


GitHub 地址:

https://github.com/indulgeIn/YBHandyTableView


640?wx_fmt=gif一、传统方式的弊端


UITableView是出场率极高的视图组件,开发者通过实现<UITableViewDataSource>和<UITableViewDelegate>协议方法来配置布局逻辑,面向协议设计模式在苹果的代码设计中很常见,它能适应大部分的业务场景且足够灵活。这种方式优点很多,比如某一时刻组件只需要关心当前需要的数据,避免了多余的计算,同时也可以让数据及时释放减小内存峰值。UITableView相关的协议方法充分体现了单一职责原则,比如一个协议方法返回 Cell 的高度,一个协议方法返回 Cell 的实例。


然而当某一个界面结构比较复杂且多元的时候,开发者往往需要写大量的if/else/else if或switch分支语句来区分不同section/row的视图类型及其布局,由于UITableView相关协议方法的职责单一性,这种分支语句会重复出现在多个协议方法里面。


显然在这种场景下,UITableView变得不那么优雅。


640?wx_fmt=gif二、常规优化思路


理所当然的,大家很容易想到使用一个中间类来将协议过于分散的管理方式集中起来:


@interface CellLayout : NSObject
@property (nonatomicstrong) Class cellClass;
@property (nonatomicassignCGFloat cellHeight;
@property (nonatomicstrong) AnyModel *cellModel;
...
@end


然后在UITableView相关各个协议方法里从NSArray<CellLayout *> layoutArray数组中拿到数据配置就行了,如此,开发者只需要关心如何构建layoutArray数组,避免了写过多的分支语句。


这种思路有两点需要注意:


需要一个包含某个 Cell 所有布局信息的中间类

在中间类确定的情况下,<UITableViewDataSource>和<UITableViewDelegate>协议方法里面的逻辑就已经可以共用了。

笔者思考过后,花了一天时间做了一个小组件

https://github.com/indulgeIn/YBHandyTableView

它解决的问题是让开发者更轻松、更优雅的使用UITableView,核心操作就是用数组来替代协议方法为UITableView配置数据。当然,这么做有它的局限性,后文再来分析。


640?wx_fmt=gif三、组件架构设计


640?wx_fmt=jpeg


经过前面的分析,组件要做的事情有两个,一个是设计一个中间类,一个是封装<UITableViewDataSource>和<UITableViewDelegate>协议方法的实现。


640?wx_fmt=gif核心思路


按照常规的思路,可能会想到设计一个通用的中间类,就像之前说的CellLayout,然后利用继承的特性来为CellLayout添加额外的属性(比如数据model)。这样确实能达到目的,不过这样带来了较为严重的耦合,需要开发者一开始就知道他必须写一个类来继承自你的CellLayout,若本身业务中需要继承另外一个类就很蛋疼了(毕竟 OC 不支持多继承);再者,若某一天想要剔除这种方案可能会很麻烦,CellLayout设计得越臃肿、包含的业务越多将越难剥离。


并且,一个CellLayout是解决不了问题的,因为配置UITableView可能需要UITableViewCell的一些数据,也需要一些通用的方法来告知UITableViewCell何时配置数据刷新UI,也就意味着按照这种逻辑,还需要写一个BaseTableViewCell......


显然,这种方式并不优雅,也违背了依赖倒置原则。


笔者的做法是将这个“中间类”抽象出来,作为两个协议:YBHTCellProtocol和YBHTCellModelProtocol,这两个协议包含了布局UITableView所需的数据,当然可以结合自己的业务扩充这两个协议。YBHTCellProtocol由自定义的UITableViewCell来实现;YBHTCellModelProtocol随意开发者用什么类来实现,通常情况下,使用包含UITableViewCell所需数据的Model来实现是最快捷的做法(可看Demo中的使用案例)。


640?wx_fmt=gif保证深度定制性


考虑到一个问题,UITableView相关协议方法非常多,若为YBHTCellProtocol和YBHTCellModelProtocol拓展所有的配置将会需要大量的代码,可能有些得不偿失。


所以笔者使用多代理 (YBHandyTableViewProxy) 来保证组件使用方深度定制的需求,也是为了避免某些特殊情况下,使用该组件的业务模块能快速的拓展之前没有的功能:


- (void)ybht_addDelegate:(id<UITableViewDelegate>)delegate;
- (void)ybht_addDataSource:(id<UITableViewDataSource>)dataSource;


当然这样做会有隐患,所以建议读者朋友若想使用该组件先了解它的原理,该组件的代码不多也不高深,相信只要感兴趣的朋友能很快理解。


640?wx_fmt=gif四、组件的弊端


组件的配置方式很简单:


NSArray<id<YBHTCellModelProtocol>> tmpArr = ...;
[anyTableView.ybht_rowArray addObjectsFromArray:tmpArr];
[anyTableView reloadData];


正如代码所见,需要传入的是实现YBHTCellModelProtocol协议的实例,同时需要对应的UITableViewCell实现YBHTCellProtocol协议(可对比 UML 类图)。


取个例子,若你在UIViewController里面写了一个UITableView,然后使用该组件配置数据,可以明确的是组件将<UITableViewDataSource>和<UITableViewDelegate>协议封装起来,UIViewController和你定制的那些UITableViewCell已经没有了耦合,也就意味着,它们之间的交互将不能直接进行。


640?wx_fmt=gif那么,它们如何间接的交互呢?


1.YBHandyTableViewIMP是组件实现<UITableViewDataSource>和<UITableViewDelegate>协议的类,那么将UIViewController对象传入到该类就能实现与UITableViewCell的交互,但是由于YBHandyTableViewIMP和UITableViewCell不直接依赖而是都依赖于YBHTCellProtocol协议,这为定制性的交互带来了困难。


2.从另一个方面思考问题,从组件的使用方法可知,UIViewController和id<YBHTCellModelProtocol>之间是有关联的,而id<YBHTCellModelProtocol>与UITableViewCell<YBHTCellProtocol>是有关联的,所以可以通过id<YBHTCellModelProtocol>将UIViewController传递到UITableViewCell中,然后进行交互。


3.基于响应链的传递路径来拦截事件。这种方式比较巧,但是却始终感觉不是那么稳妥,它的好处是处理UITableViewCell的交互事件完全可以不经过该组件就能完成。


最后,笔者建议使用第二种方式。不过不管哪种方式来说都不太优雅了,在业务开发中应该多考虑一下,UITableViewCell中会不会有大量的事件需要传递到最外层的业务,比如跳转界面、网络请求等就可以直接在UITableViewCell里面处理。若大量的交互是必然的(或者说是为了满足业务架构规范),那就放弃“偷懒”,专门设计一个适合业务的方式吧。


640?wx_fmt=gif五、结语


本文是笔者做的一个小实践的思路分享,需要明白的是,一个代码设计并非能满足所有的业务,特别是这种和具体业务紧密相连的组件。在一开始笔者还满怀希望,觉得这个组件的场景很大,后来发现有很多局限性。


组件总是会让粒度变大,当你追求更小粒度的时候你会发现:我去,好像这个组件没有了意义?。


 推荐↓↓↓ 

640?wx_fmt=png

?16个技术公众号】都在这里!

涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。

觉得我们“好看”的点亮它~
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS 架构组件:让你的 TableView 优雅起来 的相关文章

  • 将Enum枚举转成Map,List结构

    JAVA枚举功能强大 感觉就像是一种简化版的类对象 可以有构造方法 可以重载 可以继承接口等等 JAVA枚举在实际开发中应用相当频繁 以下几个封装方法在实际开发中可能用到 将枚举类转化为Map以及List结构的一些操作方法 首先 新建一个枚
  • qt file not found 原因之一

    14 error h file not found 原因之一 在pri中说明的cpp文件 如果其中 include 本pri定义的其它文件 则会直接以此cpp文件为基础进行寻找 在 include 文件时 可以在cpp文件所在目录下 或以此
  • Qt中父子widget的事件传递

    以前我一直以为 在父widget上摆一个子widget后 当click子widget时 只会进入到子widget的相关事件处理函数中 比如进入到mousePressEvent 中 而不会进入到父widget的对应事件处理函数中 毕竟 cli
  • ajax跨域post请求数据_基于Python的Post请求数据爬取

    为什么做这个 和同学聊天 他想爬取一个网站的post请求 观察 该网站的post请求参数有两种类型 1 参数体放在了query中 即url拼接参数 2 body中要加入一个空的json对象 关于为什么要加入空的json对象 猜测原因为反爬虫
  • 《OSPF和IS-IS详解》一1.7 独立且平等

    本节书摘来自异步社区 OSPF和IS IS详解 一书中的第1章 第1 7节 作者 美 Jeff Doyle 更多章节内容可以访问云栖社区 异步社区 公众号查看 1 7 独立且平等 OSPF和IS IS详解与TCP IP相比 OSI协议对各国
  • shell命令之cp复制拷贝

    1 复制文件到文件中 cp file1 file2 file1 file2 表示某一文件 在当前目录下 将file1 的文件内容复制到file2 文件中 如果第二个文件不存在 则先创建文件 然后再拷贝内容 如果存在则直接覆盖 没有警告 加
  • C++ 函数指针

    include
  • 基于SSM+JSP的宠物医院信息管理系统

    项目背景 21世纪的今天 随着社会的不断发展与进步 人们对于信息科学化的认识 已由低层次向高层次发展 由原来的感性认识向理性认识提高 管理工作的重要性已逐渐被人们所认识 科学化的管理 使信息存储达到准确 快速 完善 并能提高工作管理效率 促
  • bp利率最新消息是多少,bps利率是什么意思

    武汉房贷利率最新消息2022 3月26日起 武汉房贷利率将下调48BP 首套房贷款利率为5 2 二套房为5 4 其实武汉下调房贷利率也是在意料之内 此前的利率放在全国范围内比较 其实是比较高的 那利率降低后 每月能省多少钱呢 武汉房贷利率最
  • SSM框架和Spring Boot+Mybatis框架的性能比较?

    SSM框架和Spring Boot Mybatis框架的性能比较 没有一个绝对的答案 因为它们的性能受到很多因素的影响 例如项目的规模 复杂度 需求 技术栈 团队水平 测试环境 测试方法等 因此 我们不能简单地说哪个框架的性能更好 而是需要
  • qt 使用uic.exe 生成ui_xxxx.h文件的方法

    自己遇到这个问题 看了下别人的回答 总是有些不太清楚 就自己完善了下 1 制作好自己的xxxx ui文件 2 确定uic exe文件的地址 比如我的就是 D Anaconda3 pkgs qt 5 9 7 vc14h73c81de 0 Li
  • 雪糕的最大数量 排序+贪心

    雪糕的最大数量 雪糕的最大数量 题目描述 样例 数据范围 思路 代码 题目描述 夏日炎炎 小男孩 Tony 想买一些雪糕消消暑 商店中新到 n 支雪糕 用长度为 n 的数组 costs 表示雪糕的定价 其中 costs i 表示第 i 支雪
  • 于仕琪老师libfacedetection最新开源代码使用测试配置

    一 首先要感谢于老师的分享 二 此教程只是方便像我这样编程小白入门使用 若有不足之处 请原谅 网上对libfacedetection的介绍已经很多了 我在这里就不进行多余的解释 直接进入主题 下载地址 https github com Sh
  • Fsm2 Fsm2

    This is a Moore state machine with two states two inputs and one output Implement this state machine This exercise is th
  • 时序预测

    时序预测 MATLAB实现DBN深度置信网络时间序列预测 目录 时序预测 MATLAB实现DBN深度置信网络时间序列预测 预测效果 基本介绍 模型描述 程序设计 参考资料 预测效果 基本介绍 BP神经网络是1968年由Rumelhart和M
  • QMainwindow中添加的其他组件无法发送消息调用槽函数

    QMainwindow中添加的其他组件无法发送消息调用槽函数 问题所在 解决办法 问题所在 include mainwindow h include ui mainwindow h include QDebug include QMessa
  • [超实用]Java返回结果的工具类

    在做项目中 处理完各种业务数据后都需要返回值告诉前端最后的操作结果 但又不能直接返回一串错误代码信息 这个时候结果处理工具类就起了有比较好的作用 在此记录下 比较简单返回结果处理方法供大家参考学习 1 结果返回处理业务类 package r
  • python123.io---双一流高校及所在省份统计

    双一流高校及所在省份统计 类型 Python 组合数据类型 字典 d 中存储了我国 42 所双一流高校及所在省份的对应关系 请以这个列表为数据变量 完善 Python 代码 统计各省份学校的数量 d 北京大学
  • vue安装Base64转码

    第一步 项目文件路径下运行 npm install save js base64 或者 cnpm install save js base64 第二步 main js文件中引入 const Base64 require js base64
  • vue——vue-video-player插件实现rtmp直播流

    更新 flash已不可再使用 大家另寻出路吧 安装前首先需要注意几个点 vue video player插件 其实就是 video js 集成到 vue 中 所以千万不要再安装 video js 可能会出错 视频流我这个项目选择rtmp格式

随机推荐

  • 3559摄像头

    input aoni Webcam as devices platform soc 12310000 xhci 1 usb1 1 1 1 1 1 0 input input0 yuv转 的代码 https github com 198708
  • DC/DC闭环控制的丘克(Cuk)变换电路原理设计及实验仿真

    如果将降压 Buck 变换电路和升压 Boost 变换电路的拓扑结构进行对偶变换 即Boost变换电路和Buck变换电路串联在一起得到一种新的电路拓扑结构 丘克 CUK 变换电路 如图所示 Cuk变换电路的输入和输出均有电感 增加电感的值
  • matlab画圆并生成随机数

    A区域生成随机数 画圆 t 0 pi 100 2 pi x 10 cos t 30 3 y 10 sin t 89 8 plot x y r 生成随机数 a zeros 2 8 i 1 while i lt 8 temp1 rand 1 2
  • node中间件是什么意思?

    node中间件是什么意思 2020 09 11 16 11 17分类 常见问题 Node js答疑阅读 1757 评论 0 中间件是一种独立的系统软件或服务程序 分布式应用软件借助这种软件在不同的技术之间共享资源 中间件位于客户机 服务器的
  • Spark SQL 项目:实现各区域热门商品前N统计

    一 需求1 1 需求简介这里的热门商品是从点击量的维度来看的 计算各个区域前三大热门商品 并备注上每个商品在主要城市中的分布比例 超过两个城市用其他显示 1 2 思路分析使用 sql 来完成 碰到复杂的需求 可以使用 udf 或 udaf查
  • 四位均衡磨损格雷码

    什么是均衡磨损格雷码 均衡磨损格雷码是一种与标准格雷码具有相同的迭代后只变化一个位的特性 但每一个数位变化的次数相近的编码 为什么要均衡磨损 由于继电器输出PLC比晶体管输出PLC具有更好的可靠性 如果用继电器输出的PLC代替晶体管输出PL
  • 从0开始用shell写一个tomcat日志清理脚本

    一 目的 tomcat日志随着时间的流逝会越来越大 虽然我们可以使用cronolog对tomcat输出的日志根据日期进行切割 但是日子一长 进到logs 文件夹下都是密密麻麻的日志 不好查看也浪费了大量的空间 故本文的目的是编写一个脚本 能
  • linux 0.11 int80实现,Linux0.11内核--系统中断处理程序int 0x80实现原理

    extern int sys setup 系统启动初始化设置函数 kernel blk drv hd c 71 extern int sys exit 程序退出 kernel exit c 137 extern int sys fork 创
  • 神经网络学习小记录68——Tensorflow2版 Vision Transformer(VIT)模型的复现详解

    神经网络学习小记录68 Tensorflow2版 Vision Transformer VIT 模型的复现详解 学习前言 什么是Vision Transformer VIT 代码下载 Vision Transforme的实现思路 一 整体结
  • 尘技-教你如何造安全相关文章

    介绍 写文章不仅仅能够总结自己的知识 还能为他人提供帮助 以及 我为自己代言 稿费 曝光度等等 如何能有思路的制造文章 下面由我慢慢道来 造文种类 造文可以分为总结类 创新类 实录类 见解类 工具分享类等等 每种类型的文章 都有自己的造文套
  • JDK自带JVM监控jvisualvm.exe 观察JVM内应用程序

    无论在测试环境还是在生产环境 我们都想知道程序在JVM中是否正常运行 除了使用第三方的一些工具 最直接的就是使用JDK自带的jvisualvm exe 系统主界面操作 JVM提供了本地的JVM监控 远程的JMX监控和快照服务 VM示例 Vi
  • 本地CPU部署运行ChatGLM2-6B模型

    1 前期准备 需要下载模型文件 2 部署过程及碰到的问题 1 编译安装python 3 8 13 Asianux release 7 6 18 gcc 4 8 5 按运行的要求需要安装torch的 gt 2 0 因此安装了torch的2 0
  • 网站打不开如何解决?教你4个方法搞定它!

    网站打不开如何解决 教你4个方法搞定它 网站如果打不开了 会影响正常的使用 并且对于SEO关键词排名还是有影响的 那么网站打不开如何解决 可能对于不懂技术的客户来说这是个着急的问题 突然发现自己的网站打不开了 不知所措 如果再遇到这样的问题
  • 记录一次elasticsearch挂掉之后无法启动 kibana Status: Red -分析过程

    记录一次elasticsearch挂掉之后无法启动 kibana Status Red 分析过程 现象 现象一 kibana Status Red 现象二 elasticsearch 集群挂掉 现象三 elasticsearch 重启 检查
  • 群晖DSM7.2 系统Web Station配置NodeJS类型网站访问方法

    平时也不怎么更新系统 最近因为用SH方式架设运行的NodeJS网站Express用着有点小问题 其中细节还需要测试原因 在更新了一堆套件之后 又看到了 系统更新的小细点 一时手残便点了更新 然后就来到了DSM 7 2 64570 Updat
  • 2014年1月30日-2月6日,(共4小时,剩4682小时)

    过年期间 初五学了3小时 初七晚上1小时 共4小时 受打击很大 好好努力吧
  • 常用表单正则表达式

    校验 大小写字母 汉字 export const verifyCheEng a zA Z p sc Han gu 校验 数字 大小写字母 汉字 export const verifyCheEngNum a zA Z0 9 p sc Han
  • LZW编码

    LZW Lempel Ziv Welch 编码又称字串表编码 是Welch将Lemple和Ziv所提出来的无损压缩技术改进后的压缩方法 GIF图像文件采用的是一种改良的LZW压缩算法 通常称为GIF LZW压缩算法 下面简要介绍GIF LZ
  • 实测视频!为什么独立比贴片IMU更适合智能驾驶?

    在汽车智能化这场行业变革中 作为智能驾驶的标配 高精度定位系统已成L2级及以上智能驾驶 照进现实 进程中四两拨千斤的存在 惯性测量单元IMU因其工作不依赖包括卫星在内的外界信号 已是智能汽车高精度定位系统的核心元器件 然而行业对于IMU应如
  • iOS 架构组件:让你的 TableView 优雅起来

    看什么看 点我呀 全栈程序员 免费入门到精通 作者丨indulge inhttps www jianshu com p 7db73489ad99 GitHub 地址 https github com indulgeIn YBHandyTab