美文网首页
应用层架构之重构Controller

应用层架构之重构Controller

作者: 你weixiao的时候很美 | 来源:发表于2018-04-28 15:46 被阅读33次

本篇在 应用层架构之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 各种类
    1. controller类。
      强引用CDDView(作为他管理的View)。
      强引用Context,controller处理的逻辑,可以交给context中的presenter,interactor,CDDView处理。
      强引用adapter(如果有adapter)。
    1. context类,通讯用的核心类。
      通过强引用持有presenter,interactor,CDDView,下发任务和逻辑。
      cddView 和 之view 通过runtime弱引用context来通讯,
      controller通过强引用context来通讯。
  • 3.CDDView类,用来代替Controller持有的那个view的类。
    CDDView通过 runtime弱引用持有context
    CDDView类通过弱引用持有 presenter(我觉得可以去掉,直接通过context来访问到presenter即可)
    CDDView类通过弱引用持有 和 interactor(我觉得可以去掉,直接通过context来访问到interactor即可)
    controller直接持有,presenter弱引用持有,可以访问到cddView及其子view。
    子view通过context,可以访问到cddView及其子view。

    1. CDDPresenter类,是具体的逻辑实现类。
      通过弱引用持有CDDView,
      通过弱引用持有controller,
      通过弱引用持有adapter(如果有adapter),
      cddView 可以通过弱引用直接通知presenter(我觉得可以去掉)
      cddView,子View,controller通过context访问到presenter。
      presenter做逻辑。
    1. CDDInteractor类,路由类。
      持有controller的弱引用,行使router的功能。
      cddView可以通过弱引用直接访问到interactor(我觉得可以去掉)
      cddView,controller,子view通过context访问到interactor。
3.2 优化后

因为cddView通过runtime赋值context,从context即可访问到presenter和interactor,所以cddView不需要弱引用持有二者。说以,我对原来的实现细节做了优化,去掉了cddView引向presenter和interactor的线。 这样,数据的流通就很容易看出


优化后.png

如图:

  • 1.数据从controller 到 context,到cddView 到 子View。
  • 2.然后子View和cddView的数据通过context 到 interactor和presenter。
    1. 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

相关文章

网友评论

      本文标题:应用层架构之重构Controller

      本文链接:https://www.haomeiwen.com/subject/wskzkftx.html