架构模式

2021-11-08  本文已影响0人  浅墨入画

架构设计-轻量化VC

MVC架构
MVC架构图

我们在使用MVC架构的时候会有耦合度的问题,如下所示

image.png

以下案例来说明

image.png image.png image.png

上面的代码可以在cell中更改数据源,违背了架构的原则,model层与view层产生了耦合。架构的原则是高内聚,低耦合,谁的事情谁做

VC的意义
VC的意义 image.png
@property (nonatomic, strong) Present           *pt;

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 数据提供层,让model自带数据
    self.pt = [[Present alloc] init];
}
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef void (^CellConfigureBefore)(id cell, id model, NSIndexPath * indexPath);

@interface LMDataSource : NSObject<UITableViewDataSource,UICollectionViewDataSource>
@property (nonatomic, strong)  NSMutableArray *dataArray;;

//自定义
- (id)initWithIdentifier:(NSString *)identifier configureBlock:(CellConfigureBefore)before;

@property (nonatomic, strong) IBInspectable NSString *cellIdentifier;
@property (nonatomic, copy) CellConfigureBefore cellConfigureBefore;
- (void)addDataArray:(NSArray *)datas;
- (id)modelsAtIndexPath:(NSIndexPath *)indexPath;
@end

<!-- LMDataSource.m -->
#import "LMDataSource.h"

@implementation LMDataSource

- (id)initWithIdentifier:(NSString *)identifier configureBlock:(CellConfigureBefore)before {
    if(self = [super init]) {
        _cellIdentifier = identifier;
        _cellConfigureBefore = [before copy];
    }
    return self;
}


- (void)addDataArray:(NSArray *)datas{
    if(!datas) return;
    if (self.dataArray.count>0) {
        [self.dataArray removeAllObjects];
    }
    [self.dataArray addObjectsFromArray:datas];
}

- (id)modelsAtIndexPath:(NSIndexPath *)indexPath {
    return self.dataArray.count > indexPath.row ? self.dataArray[indexPath.row] : nil;
}

#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return !self.dataArray  ? 0: self.dataArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];
    id model = [self modelsAtIndexPath:indexPath];
    if(self.cellConfigureBefore) {
        self.cellConfigureBefore(cell, model,indexPath);
    }
    return cell;
}

#pragma mark UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return !self.dataArray  ? 0: self.dataArray.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:self.cellIdentifier forIndexPath:indexPath];
    id model = [self modelsAtIndexPath:indexPath];
    if(self.cellConfigureBefore) {
        self.cellConfigureBefore(cell, model,indexPath);
    }
    return cell;
}

- (NSMutableArray *)dataArray{
    if (!_dataArray) {
        _dataArray = [NSMutableArray arrayWithCapacity:5];
    }
    return _dataArray;
}
@end
image.png

架构设计-MVP构建

- (void)setNum:(int)num{
    _num                = num;
    self.numLabel.text  = [NSString stringWithFormat:@"%d",self.num];
    // 去掉更改数据的操作
}

// viewDidLoad方法修改
self.dataSource = [[LMDataSource alloc] initWithIdentifier:reuserId configureBlock:^(MVCTableViewCell *cell, Model *model, NSIndexPath *indexPath) {
    cell.numLabel.text  = model.num;
    cell.nameLabel.text = model.name;
}];

运行工程点击页面,更改页面数据,滑动页面之后数据又变成初始化的数据。

这里推荐面向协议思想MVP架构,解决上面model层与UI层的通信。

@protocol PresentDelegate <NSObject>
// 需求: UI num -> model
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
@end

@interface Present : NSObject<PresentDelegate>
@property (nonatomic, strong) NSMutableArray    *dataArray;
@property (nonatomic,weak) id<PresentDelegate> delegate;
@end

<!-- Present.m实现协议方法 -->
#pragma mark -PresentDelegate
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath{
    // 保证数据的安全性
    @synchronized (self) {
        if (indexpath.row<self.dataArray.count) {
            Model *model = self.dataArray[indexpath.row];
            model.num = num
        }
    }
}
image.png image.png

架构设计-MVP思想总结

现在我们又了新的需求,比如说点击页面更新数据,当数据大于6时,数据源的更新又会导致页面重新布局

<!-- Present.h -->
@protocol PresentDelegate <NSObject>
// 需求: UI num -> model
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
- (void)reloadUI;
@end

<!-- Present.m -->
#pragma mark -PresentDelegate
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath{
    @synchronized (self) {
        if (indexpath.row<self.dataArray.count) {
            Model *model = self.dataArray[indexpath.row];
            model.num = num
            if ([num intValue] > 6) {
                [self.dataArray removeAllObjects];
                NSArray *temArray =
                @[
                  @{@"name":@"Hank",@"imageUrl":@"http://Hank",@"num":@"99"},
                  @{@"name":@"Kody",@"imageUrl":@"http://Kody",@"num":@"99"}];

                for (int i = 0; i<temArray.count; i++) {
                    Model *m = [Model modelWithDictionary:temArray[i]];
                    [self.dataArray addObject:m];
                }
                
                // model - delegate -> UI
                if (self.delegate && [self.delegate respondsToSelector:@selector(reloadUI)]) {
                    [self.delegate reloadUI];
                }
            }
        }
    }
}
@interface MVCViewController ()<PresentDelegate>

#pragma mark -PresentDelegate
- (void)reloadUI{
    [self.dataSource addDataArray:self.pt.dataArray];
    [self.tableView reloadData];
}
- (void)viewDidLoad { 
    self.pt.delegate = self;
}
小结

上面我们的流程是UI更新 -> 数据更新 -> UI更新,实现了双向通信。即双向绑定
MVP思想步骤:根据需求 -> 接口设计 -> 功能实现MVVM更多的是面向block,如果block嵌套层次过深,会很难定位问题,而且数据安全会存在很大问题,维护成本会很高。面向协议开发是点对点,就能避免层级过深的问题。

架构设计-适配器设计

上面的案例虽然使用了MVP设计模式,但是页面比较简单只有一个类型的cell,如果有多个类型的cell,该怎么设计呢?

使用适配器设计加载不同类型cell

适配器加载多类cell使用
<!-- KCHomeAdapter.h -->
#import "KCBaseAdapter.h"

NS_ASSUME_NONNULL_BEGIN
@interface KCHomeAdapter : KCBaseAdapter
@end
NS_ASSUME_NONNULL_END

<!-- KCHomeAdapter.m -->
#import "KCHomeAdapter.h"
#import "KCHomeTableViewCell.h"
#import "KCChannelProfile.h"

@implementation KCHomeAdapter

- (CGFloat)getCellHeight:(NSInteger)row
{
    CGFloat height = SCREEN_WIDTH*608/1080 + 54;
    KCChannelProfile *model = [self.getAdapterArray objectAtIndex:row];
    if (model.title.length > 0) {
        CGSize titleSize = [model.title sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]}];
        if (titleSize.width > SCREEN_WIDTH - 35) {
            // 两行
            height +=67;
        }else{
            height +=50;
        }
    }else{
        height += 8;
    }
    return height;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self getCellHeight:indexPath.row];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.getAdapterArray.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    // 二次封装 网络数据回来之后
    // sucess
    // model
    // 定制化处理
    KCChannelProfile* liveModel = self.getAdapterArray[indexPath.row];
    UITableViewCell *cell = nil;
    // 适配下发
    CCSuppressPerformSelectorLeakWarning (
                                          cell = [self performSelector:NSSelectorFromString([NSString stringWithFormat:@"tableView:cellForKCChannelProfile:"]) withObject:tableView withObject:liveModel];
                                          );
    return cell;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForKCChannelProfile:(id)model {
    NSString *cellIdentifier = NSStringFromSelector(_cmd);
    KCHomeTableViewCell *cell = (KCHomeTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[KCHomeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    
    KCChannelProfile* liveModel = model;
    [cell setCellContent:liveModel];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    id model = self.getAdapterArray[indexPath.row];
    if (self.adapterDelegate && [self.adapterDelegate respondsToSelector:@selector(didSelectCellData:)]) {
        [self.adapterDelegate didSelectCellData:model];
    }
}
@end

架构设计-context设计

架构设计-context分发

上一篇下一篇

猜你喜欢

热点阅读