架构设计模式

iOS 项目中对 MVVM 实践

2018-12-10  本文已影响127人  人魔七七

前言

针对最近研究的一些知识点的实战,抽出一个模块对项目进行优化升级。

架构注意的两点

职责界限划分以及模块之间的通信

  1. 职责界限划分
  1. 模块之间的通信

上层的组件持有下层组件的引用,下层组件不可以拥有上层组件的引用。
但是可以通过callback来处理,比如控制器观察ViewModel的方式通知控制器数据的变化,以便于控制器告诉View要update数据。

各模块的大致代码结构

Model

大致流程是从JSON映射到Model,Model属性可能需要我们自己重命名(可能服务器满足不了我们),Model最好能满足持久化需求,比如我要把某个Model存文件来缓存提供下一次使用。

ViewModel

NS_ASSUME_NONNULL_BEGIN

@interface WCSDurableGoodsRecipientsListViewModel : NSObject

#pragma mark - In 请求服务器或者本地缓存需要的参数

@property (copy, nonatomic) NSString *accountId;
@property (copy, nonatomic) NSString *searchTime;
@property (assign, nonatomic) NSInteger start;

#pragma mark - Out 界面上展示的数据

@property (copy, nonatomic) NSString *totalAppleyeStr;
@property (copy, nonatomic) NSString *awaitStr;
@property (strong, nonatomic) NSMutableArray *tableViewDataArray;

#pragma mark - NetWorkStatus 网络的状态

@property (strong, nonatomic) NetWorkResults *netWorkResults;


#pragma mark - Out 界面用户的事件

- (void)refresh;
- (void)loadMore;

@end

一个处理数据反馈状态的类

typedef NS_ENUM(NSInteger, NetWorkResultStatus) {
    NetWorkResultStatusSuccess = 0,
    NetWorkResultStatusError = 1,
    NetWorkResultStatusLoading = 2,
    
};
@interface NetWorkResults : NSObject

@property (assign,readonly) NSInteger status;
@property (nonatomic,readonly) id content;
- (instancetype)initWithStatus:(NSInteger)status content:(id)content;

@end

Controller

这里主要是我们调用ViewModel的方法,以及监听ViewModel的界面数据的变化来更新我们的View界面。这里是观察数据代码

#pragma mark - KVO

- (void)wcs_handleViewModelUpdate
{
    [self.KVOController observe:self.durableGoodsRecipientsListViewModel keyPath:FBKVOKeyPath(self.durableGoodsRecipientsListViewModel.tableViewDataArray) options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
        
        id newValue = change[NSKeyValueChangeNewKey];
        self.dataSourceArray = [(NSMutableArray *)newValue copy];
        [self.tableView reloadData];
       
    }];
    [self.KVOController observe:self.durableGoodsRecipientsListViewModel keyPath:FBKVOKeyPath(self.durableGoodsRecipientsListViewModel.netWorkResults) options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
        
        id newValue = change[NSKeyValueChangeNewKey];
        if ([newValue isKindOfClass:[NetWorkResults class]])
        {
            NetWorkResults *result = (NetWorkResults *)newValue;
            if (result.status == NetWorkResultStatusError)
            {
                [self showHUDWithTitle:@"" subTitle:result.content];
            }
        }
        
    }];
}

注意:

#define FBKVOKeyPath(KEYPATH) \
@(((void)(NO && ((void)KEYPATH, NO)), \
({ const char *fbkvokeypath = strchr(#KEYPATH, '.'); NSCAssert(fbkvokeypath, @"Provided key path is invalid."); fbkvokeypath + 1; })))

#define FBKVOClassKeyPath(CLASS, KEYPATH) \
@(((void)(NO && ((void)((CLASS *)(nil)).KEYPATH, NO)), #KEYPATH))

对于一些特殊的子View处理比如Cell

可以针对cell创建一个ViewModel,在TableViewModel中处理下。
- (NSArray *)viewModelsDurableGoodsRecipients:(WCSDurableGoodsRecipientsListModelV2 *)applyrecords
{
    NSMutableArray *viewModels = [NSMutableArray arrayWithCapacity:applyrecords.body.applyRecords.count];
    
    for (WCSDurableGoodsRecipientsListApplyrecordsModelV2 *applyrecordsModelV2 in applyrecords.body.applyRecords) {
        WCSDurableGoodsRecipientsListCellV2ViewModel *goodsRecipientsListCellV2ViewModel = [[WCSDurableGoodsRecipientsListCellV2ViewModel alloc] initWithGoods:applyrecordsModelV2];
        [viewModels addObject:goodsRecipientsListCellV2ViewModel];
    }
   
    
    return viewModels.copy;
}

cell中的处理
- (void)bindViewModel:(WCSDurableGoodsRecipientsListCellV2ViewModel *)viewModel
{
//    NSString *textStr = viewModel.applyrecordsModelV2.applyDesc;
}
控制器里的处理
- (void)configureCell:(WCSDurableGoodsRecipientsListCellV2 *)cell withObject:(WCSDurableGoodsRecipientsListCellV2ViewModel *)object
{
    [cell bindViewModel:object];
}

架构图

架构图
上一篇下一篇

猜你喜欢

热点阅读