之前的解耦架构生成器在实际项目中已经顺利测试通过了, 现在要做的是将文档规范出来, 并扩展到Android, html5端的共用, 实现面向文档开发.
- #import <UIKit/UIKit.h>
- #import <WonderfulMallHome.pb.h>
- @protocol HYSpecialSaleViewOperation <NSObject> //定义视图操作需求
- - (void)pushToNextViewController:(NSString *)targetUrl;
- - (void)pullDownRefresh;
- @end
- @protocol HYSpecialSaleModelInterface <NSObject> //定义传输数据类型
- @property(nonatomic) NSInteger tabId ;
- @property(nonatomic,strong) NSMutableArray * activityTemplates ;
- @end
- @protocol HYSpecialSaleViewModelInterface <NSObject> //定义网络通信接口
- @property (nonatomic,strong) id<HYSpecialSaleModelInterface> model;
- - (void)initializeWithParameter:(NSDictionary *)parameter finishedCallBack:(void(^)())finishCallBack;
- - (void)pullDownRefreshWithFinishedCallBack:(void(^)())finishCallBack;
- @end
- @protocol HYSpecialSaleViewInterface <NSObject>
- @property (nonatomic,strong) id<HYSpecialSaleViewModelInterface> hyspecialsaleViewModel;
- @property (nonatomic,strong) id<HYSpecialSaleViewOperation> hyspecialsaleOperation;
- @end
期望实现非开发人员通过阅读文档协议能够基础的了解该页面的大致逻辑功能, 并能够清晰的定位具体功能函数.
- ├── Template //模板文件
- │ ├── ControllerTemplate.h //控制器
- │ ├── ControllerTemplate.m
- │ ├── InterfaceTemplate.h //文档协议
- │ ├── ModelTemplate.h //传输数据类型
- │ ├── ModelTemplate.m
- │ ├── PresenterTemplate.h //视图操作需求
- │ ├── PresenterTemplate.m
- │ ├── ViewModelTemplate.h //网络通信接口
- │ ├── ViewModelTemplate.m
- │ ├── ViewTemplate.h //UI层
- │ └── ViewTemplate.m
根据文档协议, 生成各自的
,
- ModelTemplate
,
- PresenterTemplate
,
- ViewModelTemplate
, 生成的对象必须遵循文档协议的定义, 控制器用来协调
- ViewTemplate
,
- PresenterTemplate
,
- ViewModelTemplate
三者的通信
- ViewTemplate
用来统筹页面使用的数据, 类似于项目中的cachebean, 但和cachebean不同的是, 可以在model中加入状态机制, UI逻辑可以根据网络请求后的状态机制来判断显示UI, 状态的制定根据具体产品文档的定义. 代码中可以使用枚举来区分状态.
- #import <Foundation/Foundation.h>
- #import "HYSpecialSaleInterface.h"
- @interface HYSpecialSaleModel : NSObject <HYSpecialSaleModelInterface>
- @property(nonatomic) NSInteger tabId ;
- @property(nonatomic,strong) NSMutableArray * activityTemplates ;
- - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
- + (HYSpecialSaleModel *)modelWithDictionary:(NSDictionary *)dictionary;
- @end
用于统筹页面的交互逻辑, 这里的交互逻辑是需要调用接口的交互逻辑, 本职工作是用于将ViewModel的数据正确传输到View的过程, 并在此更改状态机, 用来实现UI层逻辑在View层内实现. 上一页面传输来的参数通过控制器传输至Presenter层进行保存. 每次用户交互后重置ViewModel的数据, 实现单向的动态绑定.
- #import <UIKit/UIKit.h>
- #import "HYSpecialSaleInterface.h"
- @interface HYSpecialSalePresenter : NSObject<HYSpecialSaleViewOperation>
- @property (nonatomic,assign) NSInteger tabId;
- @property (nonatomic,weak) id<HYSpecialSaleViewInterface> hyspecialsaleView;
- @property (nonatomic,weak) id<HYSpecialSaleViewModelInterface> hyspecialsaleViewModel;
- - (void)adapterWithHYSpecialSaleView:(id<HYSpecialSaleViewInterface>)hyspecialsaleView hyspecialsaleViewModel:(id<HYSpecialSaleViewModelInterface>)hyspecialsaleViewModel;
- @end
用于统筹页面的接口调用, 对Model进行持有, 使得Model不直接与任意对象进行交互,确保数据的安全性, 可将所有的数据获取及修改数据结构的逻辑封装在该层, 可以实现接口的互相调用.
- #import < Foundation / Foundation.h > #import "HYSpecialSaleInterface.h"
- @interface HYSpecialSaleViewModel: NSObject < HYSpecialSaleViewModelInterface >
- @property(nonatomic, strong) id < HYSpecialSaleModelInterface > model;
- - (void) initializeWithParameter: (NSDictionary * ) parameter finishedCallBack: (void( ^ )()) finishCallBack;
- - (void) pullDownRefreshWithFinishedCallBack: (void( ^ )()) finishCallBack;
- @end
用于UI层的展示, 所有的UI层都基于可复用的TableView, 持有用户交互操作及ViewModel数据的绑定. 在View层所有的用户交互实现直接调用文档协议中的视图操作函数即可, 不必关系具体的实现流程, 当请求完成后会更新ViewModel数据, 进行页面的刷新, 特殊的UI逻辑根据状态机进行判断即可.
- #import <UIKit/UIKit.h>
- #import "HYSpecialSaleInterface.h"
- @interface HYSpecialSaleView : UIView <HYSpecialSaleViewInterface>
- @property (nonatomic,strong) id<HYSpecialSaleViewOperation> hyspecialsaleOperation;
- @property (nonatomic,strong) id<HYSpecialSaleViewModelInterface> hyspecialsaleViewModel;
- @end
所有的函数方法的命名使用驼峰式的命名方法, 避免使用缩写, 如之前的cachebean缩写成cb这种是绝对要避免的, 对于BOOL值得命名需要在参数名前加上
来进行区分, 期望做到代码即为注释, 让非开发人员通过仅仅看代码就能够知道业务逻辑.
- is
- #import <UIKit/UIKit.h>
- @protocol <#Unit#>ViewOperation <NSObject>
- <#ViewOperation#>
- @end
- @protocol <#Unit#>ModelInterface <NSObject>
- <#ModelInterface#>
- @end
- @protocol <#Unit#>ViewModelInterface <NSObject>
- @property (nonatomic,strong) id<<#Unit#>ModelInterface> model;
- - (void)initializeWithParameter:(NSDictionary *)parameter finishedCallBack:(void(^)())finishCallBack;
- <#ViewModelInterface#>
- @end
- @protocol <#Unit#>ViewInterface <NSObject>
- @property (nonatomic,strong) id<<#Unit#>ViewModelInterface> <#unit#>ViewModel;
- @property (nonatomic,strong) id<<#Unit#>ViewOperation> <#unit#>Operation;
- @end
- {
- "super" : "", //父类的前缀
- "controller" : "Home", //控制器的前缀名
- "model" : { //模型的属性定义
- "models" : "Array"
- },
- "viewModel" : [ //获取数据的方法定义
- "register",
- "login",
- "exit",
- "refresh"
- ],
- "presenter" : [ //用户交互的方法定义
- "pushToNextViewController",
- "popToRootViewController",
- "showAlert",
- "closeButtonClick"
- ]
- }
文档模板可以通过任意数据结构进行生成, 文档模板中的
为该页面的前缀名, 如"HYHome", "HYSpecialSale"等.
- <#Unit#>
根据cacheBean相同字段, 或使用cachebean的子类, 但由于代码逻辑清晰的缘故推荐使用生成的model层.
- @property (nonatomic, assign) BOOL isPreLoad;
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- if (!_isPreLoad) {
- [self adapterView];
- _isPreLoad = YES;
- }
- }
Bool类型的参数名推荐添加
前缀, 能够让非开发人员了解是Bool值.
- is
- typedef NS_OPTIONS(NSUInteger, UIControlState) {
- UIControlStateNormal = 0,
- UIControlStateHighlighted = 1 << 0, // used when UIControl isHighlighted is set
- UIControlStateDisabled = 1 << 1,
- UIControlStateSelected = 1 << 2, // flag usable by app (see below)
- UIControlStateFocused NS_ENUM_AVAILABLE_IOS(9_0) = 1 << 3, // Applicable only when the screen supports focus
- UIControlStateApplication = 0x00FF0000, // additional flags available for application use
- UIControlStateReserved = 0xFF000000 // flags reserved for internal framework use
- };
状态机的定义可以参考系统的
的形式创建, 可实现位移叠加状态.
- UIControl
根据具体需求制定方法名, 方法如果需要调用接口建议与接口名相同或类似, 尽可能的简化参数, 达到代码及注释的原则. 方法名使用驼峰形式, 不建议用缩写, 能够准确的描述方法用处为佳.
- - (void)pushToNextViewController:(NSString *)targetUrl {
- [[HYCurrentVCmanager shareInstance].getCurrentVC hyPushDetail:targetUrl];
- }
- - (void)pullDownRefresh {
- __weak typeof(self) _self = self;
- __weak id<HYSpecialSaleViewModelInterface> __hyspecialsaleViewModel = _hyspecialsaleViewModel;
- [_hyspecialsaleViewModel pullDownRefreshWithFinishedCallBack:^{
- _self.hyspecialsaleView.hyspecialsaleViewModel = __hyspecialsaleViewModel;
- }];
- }
UI相关逻辑操作使用状态机在View层进行操作, 不建议在Presenter书写, 会造成逻辑紊乱, 接口调用的时候仅需重新赋值ViewModel, 数据及状态机会动态进行更新.
根据函数命名规范和之前类似, 请保证有传入参数及回调即可 --
.
- Parameter:(NSDictionary *)parameter finishedCallBack:(void (^)())finishCallBack
- - (void) dynamicBindingWithWithParameter: (NSDictionary * ) parameter finishedCallBack: (void( ^ )()) finishCallBack {
- [DataBase requestDataWithClass: [NSObject class] finishedCallBack: ^(NSDictionary * response) {
- NSDictionary * data = response;
- NSArray * models = data[@"models"];
- [self.models removeAllObjects];
- for (NSDictionary * dict in models) { [self.models addObject: [ModelTemplate modelWithDictionary: dict]];
- }
- finishCallBack();
- }];
- [NetWork requestDataWithType: MethodGetType URLString: @"http://localhost:3001/api/J1/getJ1List"parameter: nil finishedCallBack: ^(NSDictionary * response) {
- NSDictionary * data = response[@"data"];
- NSArray * models = data[@"models"];
- [self.models removeAllObjects];
- for (NSDictionary * dict in models) { [self.models addObject: [ModelTemplate modelWithDictionary: dict]];
- }
- [DataBase cache: [NSObject class] data: data[@"models"]];
- finishCallBack();
- }];
- }
可以在ViewModel层处理数据相逻辑的操作, 比如数据缓存, 和网络请求, 以及一些数据封装, 状态机建议写在Presenter层的回调中.
View没有什么特别的代码规范, 根据不同需求灵活使用设计模式即可, 在ViewModel赋值
方法调用的函数中可以进行状态机的判断及刷新的操作.
- set
- - (void)setHyspecialsaleViewModel:(id<HYSpecialSaleViewModelInterface>)hyspecialsaleViewModel {
- _hyspecialsaleViewModel = hyspecialsaleViewModel;
- if (!_preLoaded) { //这种判断可以使用状态机来代替.
- [self sortSubViews:@[@{@"blockType" : @(SpecialBlockTypeBlockBanner), @"showTitle" : @(NO)},
- @{@"blockType" : @(SpecialBlockTypeBlockOne), @"showTitle" : @(NO)},
- @{@"blockType" : @(SpecialBlockTypeBlockTwo), @"showTitle" : @(NO)},
- @{@"blockType" : @(SpecialBlockTypeBlockThree), @"showTitle" : @(NO)},
- @{@"blockType" : @(SpecialBlockTypeBlockFour), @"showTitle" : @(NO)},
- @{@"blockType" : @(SpecialBlockTypeBlockFive), @"showTitle" : @(NO), @"showMain" : @(YES)}]];
- _tableView.userInteractionEnabled = NO;
- _preLoaded = YES;
- } else {
- NSMutableArray * arr = [NSMutableArray array];
- for (ActivityBlock * activityBlock in hyspecialsaleViewModel.model.activityTemplates) {
- BOOL showTitle = activityBlock.blockTitle.length ? YES : NO;
- BOOL showMain = activityBlock.banners.hyArray.count == 3 ? YES : NO;
- SpecialBlockType blockType = activityBlock.blockType;
- if (blockType == SpecialBlockTypeBlockFive) {
- [arr addObject:@{@"blockType" : @(blockType), @"showTitle" : @(showTitle), @"showMain" : @(showMain)}];
- } else {
- [arr addObject:@{@"blockType" : @(blockType), @"showTitle" : @(showTitle)}];
- }
- }
- _tableView.userInteractionEnabled = YES;
- [self sortSubViews:arr];
- }
- [_tableView reloadData]; //刷新列表
- }
在View中可以直接使用之前的
的所有用户交互的函数.
- operation
文档协议的建议:
命名规范的建议:
,
- is
,
- set
,
- get
,
- did
,
- will
之类表示逻辑状态的关键字, 能够清晰的读懂方法名
- ed
UI层的建议:
具体说明可以下载Demo来进行共同探讨.
来源: https://juejin.im/post/5a18443ff265da43144064b4