本篇在 应用层架构之CDD 这篇的基础上提出,重构Controller和应用层。
这是关于CDD那篇 应用层架构之CDD
主要是借鉴本篇 深度优化Controller
重构应用层,主要分两步:
- 1.拆分,将Controller中的代码拆分到不同的类中。
- 2.组合,拆分后,不同的类需要通讯,协同工作。
1. 拆分controller
1.1 借鉴viper,mvp架构
首先借鉴了viper。但是和viper不同。将MVC拆分成了
- 子View:1.独自处理的逻辑,2. 给context传 逻辑 和 值。
- Model:数据结构存储
- CDDView:1.与之相关的逻辑,2.它能处理的相关的子View的逻辑。3.给context传逻辑 和值。
- Presenter:复杂的与各种模块都相关的流程逻辑。。
- Interactor:只执行跳转相关的逻辑,(在viper中是主要逻辑的提供者 有很多的user case)。
- adapter:tableView的代理和数据源。
1.2 和viper的比较
- 本框架和viper有相同的地方,都是将controller的代码拆分为不同的模块。
- 不同的地方:1,本架构和viper的模块的功能不同,比如interactor。2.理念不同,viper是完全的解耦,本架构没有完全的分开视图和逻辑。
1.3 使用分类
Presenter执行与全局相关的复杂的逻辑,使用category的方式,将不同的逻辑分开,拆分成Presenter+ category的方式。这样就能进一步拆分Presenter。
- Presenter+流程1
- Presenter+流程2
...
上边两个点是讲如何拆分的。
2. 通讯
- 使用cdd的方式进行通讯 ,使用runtime,给每个子view关联context。
- 使用delegate的方式来进行通讯。
关于通讯的方式有protocol-delegate,target-action,block,Notification等。几种方式的比较,objc有篇文章可以细读。
3. 详解
这里会比照demo,对重点进行详解讲解(我未来应用层是打算用这个架构的,感觉用着应该很high)
类之间关系图
3.1 各种类
- controller类。
强引用CDDView(作为他管理的View)。
强引用Context,controller处理的逻辑,可以交给context中的presenter,interactor,CDDView处理。
强引用adapter(如果有adapter)。
- controller类。
- context类,通讯用的核心类。
通过强引用持有presenter,interactor,CDDView,下发任务和逻辑。
cddView 和 之view 通过runtime弱引用context来通讯,
controller通过强引用context来通讯。
- context类,通讯用的核心类。
-
3.CDDView类,用来代替Controller持有的那个view的类。
CDDView通过 runtime弱引用持有context
CDDView类通过弱引用持有 presenter(我觉得可以去掉,直接通过context来访问到presenter即可)
CDDView类通过弱引用持有 和 interactor(我觉得可以去掉,直接通过context来访问到interactor即可)
controller直接持有,presenter弱引用持有,可以访问到cddView及其子view。
子view通过context,可以访问到cddView及其子view。 - CDDPresenter类,是具体的逻辑实现类。
通过弱引用持有CDDView,
通过弱引用持有controller,
通过弱引用持有adapter(如果有adapter),
cddView 可以通过弱引用直接通知presenter(我觉得可以去掉)
cddView,子View,controller通过context访问到presenter。
presenter做逻辑。
- CDDPresenter类,是具体的逻辑实现类。
- CDDInteractor类,路由类。
持有controller的弱引用,行使router的功能。
cddView可以通过弱引用直接访问到interactor(我觉得可以去掉)
cddView,controller,子view通过context访问到interactor。
- CDDInteractor类,路由类。
3.2 优化后
因为cddView通过runtime赋值context,从context即可访问到presenter和interactor,所以cddView不需要弱引用持有二者。说以,我对原来的实现细节做了优化,去掉了cddView引向presenter和interactor的线。 这样,数据的流通就很容易看出
优化后.png
如图:
- 1.数据从controller 到 context,到cddView 到 子View。
- 2.然后子View和cddView的数据通过context 到 interactor和presenter。
- presenter 和interactor 再到 controller和cddView。
3.3 代码分析,CDD部分代码
cdd通过runtime来给View关联了context对象。
- (void)setContext:(CDDContext*)object {
objc_setAssociatedObject(self, @selector(context), object, OBJC_ASSOCIATION_ASSIGN);
}
- (CDDContext*)context {
id curContext = objc_getAssociatedObject(self, @selector(context));
if (curContext == nil && [self isKindOfClass:[UIView class]]) {
//try get from superview, lazy get
UIView* view = (UIView*)self;
UIView* sprView = view.superview;
while (sprView != nil) {
if (sprView.context != nil) {
curContext = sprView.context;
break;
}
sprView = sprView.superview;
}
if (curContext != nil) {
[self setContext:curContext];
}
}
return curContext;
}
详解:
- 这里关联对象用的OBJC_ASSOCIATION_ASSIGN ,是弱引用。
- nsobject类都关联context属性。
- 使用while循环,通过view的树的superView方法来获取父视图的context,获取到后,设置给自己。
3.4 初始化和绑定
通过图,我们看到了结构,初始化的时候的绑定如下:
// 给controller赋值context
self.rootContext = [[CDDContext alloc] init]; //strong(属性)
self.context = self.rootContext; //weak(runtime那个)
//给context赋值presenter
self.context.presenter = [presenterClass new];
self.context.presenter.context = self.context;(runtime把context再赋值给presenter)
// 给context赋值interactor
self.context.interactor = [interactorClass new];
self.context.interactor.context = self.context;(runtime把context再赋值给interactor)
// 给context赋值CDDView
self.context.view = [viewClass new];
self.context.view.context = self.context;(给CDDView赋值context)
//给presenter和interactor赋值
self.context.presenter.view = self.context.view;
self.context.presenter.baseController = self;
self.context.interactor.baseController = self;
//给CDDView赋值()
self.context.view.presenter = self.context.presenter;
self.context.view.interactor = self.context.interactor;
//跟我我的优化,这里可以去掉不要。
//给controller赋值cddView
self.view = self.context.view;
// 这里整个绑定过程就完成了。
3.5 通过协议来通讯
//interactor
@protocol ITemplateInteractor <NSObject>
@end
//presenter
@protocol ITemplatePresenter <NSObject>
@end
//CDDView
@protocol ITemplateView <NSObject>
- (void)buildTemplateView:(EAdapter*)adapter; //有adapter的时候
- (void)reloadTemplateView;
@end
使用协议代理的方式,来进行通讯。
3.6 了解一下adapter
// 首先,设置adapter作为tableView的delegate和dataSource
@interface EAdapter : NSObject<UITableViewDataSource, UITableViewDelegate>
// 其次,公开3个代理方法来讲操作给代理。
//tableView代理
@protocol EAdapterDelegate <NSObject>
@optional
- (void)didSelectCellData:(id)cellData;
- (void)deleteCellData:(id)cellData;
- (void)willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
@end
//scrollView代理
@protocol EAdapterScrollDelegate <NSObject>
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView ;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView ;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView;
@end
// 更新代理
@protocol EAdapterPullUpDelegate <NSObject>
- (void)beginToRefresh;
@end
网友评论