iOS - 开发1年后对MVC新的理解

一·Controller层

先上代码

  • @interface Controller()
  • @property(nonatomic, strong) UITableView *tableView;
  • @end
  • @implementation Controller
  • - (void)viewDidload {
  • [super viewDidload];
  • 初始化UI
  • 懒加载
  • [self.view addSubView:xxxx];
  • }
  • - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  • _cell = [tableView dequeueReusableCellWithIdentifier:addCellId forIndexPath:indexPath];
  • _cell.model = [APIManager manager].backPackModel[indexPath.row];
  • return _cell;
  • }
  • - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
  • [tableView deselectRowAtIndexPath:indexPath animated:YES];
  • }
  • - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
  • return self.dataArray.count;
  • }
  • - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  • MVCTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuserId forIndexPath:indexPath];
  • // 不合理
  • cell.model = self.dataArray[indexPath.row];
  • return cell;
  • }
  • 相信很多人都有写过这段代码 delegate & dataSource 代理方法 导致了VC的沉重
  • @end
展开

问题来了回到工程项目需求,每个cell都有增加减少按钮 而且需要有选中效果在View层.意味着MVC架构模式中 我在View层对Model进行了修改.

再者Action操作视图逻辑代码是放在C层或V层 最终导致C层随着需求会慢慢变大变臃肿

再回过头来看项目工程目录导致VC过重的原因因素

·繁重的UI 例如tableView CollectionView

·业务逻辑 如下面的全选效果

·网络请求

·代理方法

优化代码

  • 封装一个继承自NSObject的类,遵循DataSource代理
  • @interface Controller()
  • @property(nonatomic, strong) UITableView *tableView;
  • @property(nonatomic, strong) YourDataSource *dataSource;
  • @end
  • @implementation Controller
  • - (void)viewDidload {
  • self.dataSource = [YourDataSource alloc]initWithIdentifier:reuserId
  • configBlock:^(yourCellClass *cell, Model *model, NSIndexPath *indexPath) {
  • cell.model = model; //这一句代码代表了MVC模式中的 Model->View 这一单层通道
  • }
  • [self.view addSubview:self.tableView];
  • self.tableView.dataSource = self.dataSource;
  • [self.dataSource addDataArray:[SingleManager manage].userListArr];
  • }
  • @end
  • 到这减少了 DataSource 所需要实现的代码
  • 这里不给出DataSource的封装代码 需要源码的可以加我 936101005 点个赞 ~ 拒绝伸手

二·Model层

Model层玩法就很多了,这里我通常使用单例保存在内存中看 -> 《iOS-使用GCD单例创建管理对象

第二种玩法是通过Swift混编,我们来对比一下Model层的不同

定义

  • OC层
  • @interface Model : NSObject
  • @property (nonatomic, copy) NSString *name;
  • @property (nonatomic, copy) NSString *imageUrl;
  • @property (nonatomic, copy) NSString *num;
  • @property (nonatomic, strong) NSArray <UserModel *> *userList;
  • @end
  • @interface UserModel : NSObject
  • @property (nonatomic, copy) NSString *userId;
  • @property (nonatomic, copy) NSString *group;
  • @end
  • Swift层
  • 先定义结构体 model结构
  • struct ModelBean: Coable {
  • let name: String
  • let imageUrl: String?
  • let num: Int
  • let userList : [UserModelBean]
  • }
  • struct UserModelBean: Coable {
  • let userId: String
  • let group: String
  • }

解析

我的上一篇文章写了关于数据与模型绑定的文章《NSArray与Model模型》,不熟悉的可以回过头看一看。

  • OC层
  • for (int i = 0; i<temArray.count; i++) {
  • Model *m = [Model modelWithDictionary:temArray[i]];
  • [self.dataArray addObject:m];
  • }
  • 但通常的,我会使用MJExtention封装好的三方框架来解析数据
  • mj_objectArrayWithKeyValuesArray
  • Swift
  • 通常解析数据会根据后台的数据结构返回来的JSON进行匹配
  • swift会有点麻烦 我们拿一个 数据里嵌套数组来作为例子
  • @objc public class Model: NSObject {
  • init(bean: ModelBean) {
  • name = bean.name
  • imageUrl = bean.imageUrl
  • num = bean.num
  • userList = bean.userList?.map{ .init(bean: $0)} ?? []
  • }
  • @objc public let name: String
  • @objc public let imageUrl: String?
  • @objc public let num: Int
  • @objc public let userList : [UserModelBean]
  • }
  • @objc public class UserModelBean: NSObject {
  • init(bean: UserModelBean){
  • userId = bean.userId ?? ""
  • gourp = bean.gourp ?? ""
  • }
  • @objc public let userId: String?
  • @objc public let gourp: String?
  • }

三·View层

MVC架构中model层数据传给cell通过setter与数据进行通信

  • @interface Cell : UITableViewCell
  • @property (nonatomic, strong) Model *model;
  • @end
  • @implementation Cell
  • 但是外界数据模型没有一起变化, 暴露一个接口给外界刷新UI 导致了高偶合问题
  • - (void)setNum:(int)num {
  • _num = num;
  • self.model.num = self.numLabel.text;
  • }
  • View 和 Model 进行了绑定 //到此双向绑定完成
  • - (void)setModel:(Model *)model { //setter Model 代表了MVC架构中的View -> Model view展示model数据
  • _model = model;
  • self.num = model.num;
  • self.Name = model.name;
  • self.xxx = model.xxx;
  • }
  • @end

四·MV? 架构 (Model和UI之间的消息通讯方式)

在上面我们把DataSource麻烦的代码交给了封装的DataSource类中,但是还剩下一个Delegate代理没解决

MVC (最快上手架构)

MV-Protocal (适用于复杂的多层回调)

MV-Block (适用于简单的单层回调)

创建一个数据提供层Present 也可以成为称为代理,来减少Controller的负担

  • @protocal PresentDelegate <NSObject>
  • - (void)addBtnWithNum:(int)num indexPath:(NSIndexPath *)indexPath;
  • - (void)reloadUi;
  • @end
  • @interface Present: NSObject <PresentDelegate>
  • @property (nonatomic, weak) id<PresentDelegate> delegate;
  • @end
  • @implementation Present
  • - (void)addBtnWithNum:(int)num indexPath:(NSInexPath *)indexPath {
  • @synchronized (self) {
  • if (indexPath.row < [SingleManage manage].userList.count) {
  • Model *model = [SingleManager manage].userListArr[indexPath.row];
  • model.num = num;
  • }
  • }
  • if (self.delegate && [self.delegate respondsToSelector:@selecotr(reloadUI)]) {
  • [self.delegate reloadUI];
  • }
  • }
  • @end

View层的setter方法就可以优化成

  • @interface Cell: UITableViewCell
  • @property (nonatomic, weak) id<PresentDelegate> delegate;
  • @property (nonatomic, strong) NSIndexPath* indexPath;
  • @end
  • @implementation
  • - (void)setNum:(int)num {
  • _num = num;
  • if (self.delegate && [self.delegate respondsToSelector:@selector(didClickNum:indexPath:)]) {
  • [self.delegate didClickNum:self.numLabel indexPath:self.indexPath];
  • }
  • }
  • @end

那么最终Controller层可以写成这样

  • __weak typeof(self) weakSelf = self;
  • self.dataSource = [[DataSource alloc] initWithIdentifier:reuserId configureBlock:^(MVPTableViewCell *cell, Model *model, NSIndexPath *indexPath) {
  • // 代理 model --> UI
  • cell.numLabel.text = model.num;
  • cell.nameLabel.text = model.name;
  • cell.indexPath = indexPath;
  • cell.delegate = weakSelf.pt;
  • }];
  • [self.dataSource addDataArray:[SingleManager manager].userList];
  • // UI
  • [self.view addSubview:self.tableView];
  • self.tableView.dataSource = self.dataSource;
  • self.pt.delegate = self;
本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
<<上一篇
下一篇>>