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

2022-03-10 14:36:44 浏览数 (1)

一·Controller层

先上代码

代码语言:objective-c复制
@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

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

·网络请求

·代理方法

优化代码

代码语言:objective-c复制
封装一个继承自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层的不同

定义

代码语言:javascript复制
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

代码语言:javascript复制
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模型》,不熟悉的可以回过头看一看。

代码语言:javascript复制
 OC层
 
 for (int i = 0; i<temArray.count; i  ) {
 Model *m = [Model modelWithDictionary:temArray[i]];
 [self.dataArray addObject:m];
 }
 
 但通常的,我会使用MJExtention封装好的三方框架来解析数据
 mj_objectArrayWithKeyValuesArray

代码语言:javascript复制
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与数据进行通信

代码语言:objective-c复制
@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的负担

代码语言:objective-c复制
@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方法就可以优化成

代码语言:javascript复制
@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层可以写成这样

代码语言:objective-c复制
    __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;

0 人点赞