Comments (1)
读 『如何写好一个UITableView』
一、痛点
- UITableView 的代理方法和数据源方法
- 网络请求、解析数据
- 下拉、上拉
二、MVC
- 控制器 controller 负责 model 和 view 的交互
- Model 不仅仅是一个 model 类,而是一个 model 层
- Controller 只做不能复用的事情?
- 解耦不仅仅是把代码拆开,更应该是关注代码结构的可重用性、可维护性、可扩展性。
三、传统的做法
现状
Controller 中实现 delegate 和 dataSource 方法,管理 UI 和数据、交互。
- 违背 MVC 模式,现在是 V 持有 C 和 M(?)
- C 管理了全部逻辑,耦合太严重
- 其实绝大多数 UI 相关都是由 Cell 而不是 UITableView 自身完成的(?)
数据源
总共有以下几类方法:
- Row count
- Row display
- Editing
- Moving/reordering
- Index
- Data manipulation
其中两个最常用的方法:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
代理
总共有以下几类方法:
- Display customization
- Variable height support
- Section header & footer information
- Accessories (disclosures)
- Selection
- Editing
- Moving/reordering
- Indentation
- Copy/Paste
- Focus
其中以下几个方法最常用:
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
四、优化
1. 数据源
-
基本**:将数据源方法抽取出来到一个单独的类中
-
包含哪些内容:
- 每个 DataSource 都应该有一个 SectionModels 数组,一个 Section 对应一个 SectionModel
- 每个 SectionModel 中又包含 Header、Footer、Cell 相关的数据,其中这个 section 中所有的 cell 数据都放到 CellModels 数组中
- CellModel 中可以保存 cell reuse identifier 和 cell height 缓存、以及 cell 展示信息等数据
-
实现哪些方法:下面三个方法都要在这个数据源类中实现
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- 自定义一个继承于
UITableViewDataSource
的 dataSource 协议,包含两个方法
// 每个 indexPath 对应的 cell 的 class,主要是用来给 `cellForRow` 方法创建 cell 用的,子类需要重写
- (Class)tableView:(UITableView*)tableView cellClassForModel:(SCTableViewCellModel *)model;
// 提供一个接口用于获取指定 indexPath 对应的 model
- (SCTableViewCellModel *)tableView:(UITableView *)tableView modelForRowAtIndexPath:(NSIndexPath *)indexPath;
- 自定义 Cell 要做的事情:实现
-setModel
方法,或者提供model
属性,用来接收 model 数据
2. 代理
- 两个问题
- cell 高度:跟 UI 和数据相关,应该交给 cell 自己去计算,提供 model 就行了----> cell 中提供一个计算高度的静态方法
- 点击事件:主要是根据 model 来处理,位置并不太需要关心---->定义一个继承于 UITableViewDelegate 的协议,提供一个用于处理点击事件的方法,作为系统 cell 点击方法的中转,顺便将 model 传递出来
3.如何将上面针对数据源和代理的优化串联起来
- 定义一个继承于 UITableView 的自定义 table view
- 定义两个属性
customDelegate
和customDataSource
,分别用来接收自定义数据源和自定义代理,如果数据源中有数据,自定义 table view 可以直接在内部处理一些系统的代理方法,如果没有,也可以交给外面的 controller 自己去实现 - 设置 tableView 的 delegate 为自定义 table view 自身
- 重写
customDataSource
的 setter 方法,将 dataSource 中转给UITableView
的dataSource
属性 - 在自定义 table view 中实现
UITableViewDelegate
的方法,用来计算 cell 高度,和分发点击事件等
4. 成果
- 此时的 MVC
- M 就是数据源及相关的 Model 类
- V 就是自定义的 table view
- C 就是一个更清爽的 controller,只负责创建数据源、table view,以及处理一些不能复用的逻辑
- 解决了什么痛点
- 不再需要每次写一大堆重复的 UITableView 代理方法和数据源方法
- 实现简单的数据绑定,不再需要关注代理方法和数据源方法,只需要关注数据源(Model)和 cell 自身(View)
- 更清晰的 MVC
- 如何使用
- 创建你的 View Controller,创建数据源对象,实现“数据绑定”
- 创建一个数据源子类,在数据源中重写一些基类的方法,比如 cell 的 class
- 创建自定义 cell 的子类,实现
setModel
方法、cell 高度计算的方法
5. 下一步
- 通信:cell 如何和 controller 通信 ——> 代理回调或者弱持有 controller(是不是可以搞个类似于 router 那种中间层呢)
- 下拉刷新和上拉加载的处理
- 网络请求、数据解析的处理
- (网络错误或者数据为空时的占位图)
五、网络层
1. 为什么需要网络层
- 考虑到后期更新——第三方网络库的迁移,比如由 ASI 迁移到 AFNetworking
- 需要第三方网络库基础上添加一些扩展功能,比如请求的取消,翻页,计算请求耗时,对 header 的处理等等
- 其他跟网络请求有关的自定义扩展,请求失败的 toast,空态占位图,log 等等
2. 三个环节
- 发起请求
- 集约式(命令式):只定义一个类,提供接口接受参数来发请求
- 分布式(声明式):定义一个基类,然后针对各个 API 再分别创建对应的 API Manager 子类
- 回调处理
- block
- delegate
- 数据解析
3. 实现
- 定义一个 API Manager 类
- 封装网络请求的具体实现,让调用更简单
- 扩展一些自定义功能:网络请求的状态、返回时的数据处理
- 处理一些公共逻辑:耗时统计等
- 定义 BaseItem:主要用来 JSON 解析,保存解析后的数据
- 定义 BaseModel
- 管理对应 API 的网络请求
- 管理数据模型 BaseItem
4. 实践
- 定义 BaseItem 的子类
- 定义 BaseModel 的子类,并持有 Item 和 API Manager
- 在 controller 中创建所需的 Model 对象,发起网络请求,并添加处理回调的逻辑,回调时可以从 Model 中获取到解析后 Item 数据
六、下拉刷新和上拉加载更多
1. 两个问题
- 封装 UI 细节
- 翻页
2.实现
- 继承 baseTableController,提供设置上拉下拉控件的接口和处理一些基础逻辑(比如 endRefresh 操作), 并在自定义 tableView 中处理上下拉控件的添加细节
- 继承 BaseModel,实现翻页的逻辑
七、总结
- 没有最通用的架构,只有最合适的架构
- 实际情况下,架构的设计应该是自顶向下的,先有了问题和需求,再一层一层抽象
一些思考:
核心**:复用+解耦+易于理解、逻辑清晰
- 值得借鉴之处:
- 不同看法:
- 补充:
- 空态页
- 网络错误提示 toast
- 页面缓存
from ios-app-architecture.
Related Issues (13)
- 读『杂谈: MVC/MVP/MVVM』 HOT 1
- 读『iOS应用架构谈』系列 HOT 2
- 读『 iOS Architecture Patterns: Demystifying MVC, MVP, MVVM and VIPER 』 HOT 1
- 如何成为一名合格的、优秀的架构师? HOT 1
- 浅谈 iOS 应用架构 HOT 1
- MVVM HOT 1
- MVC HOT 6
- 读『优秀的 iOS 应用架构:MVVM、MVC、VIPER,孰优孰劣?』 HOT 1
- 设计模式(一) HOT 5
- 读『Much ado about iOS app architecture』
- 如何设计 iOS 应用网络层? HOT 1
- API 设计原则 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ios-app-architecture.