首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS 组件化之CTMediator

iOS 组件化之CTMediator

作者头像
赵哥窟
发布2020-07-10 10:16:33
2K0
发布2020-07-10 10:16:33
举报

关于iOS组件化网上资料太多,这里只是从个人观点说明一下怎么使用组件化和使用组件化的优点和缺点 首先下载CTMediatorDemo

Demo的目录结构

项目在没有使用CTMediator之前模块间的关系是这样的

当ModuleA要调用ModuleB和ModuleC的时候,需要#import ModuleB,ModuleC 同样ModuleB要调用ModuleA和ModuleC的时候,需要#import ModuleA,ModuleC 这样耦合程度非常严重

使用了CTMediator之后

ModuleA,ModuleB,ModuleC之间就没有耦合了。

具体实现 CTMediator+ModuleA

#import "CTMediator.h"


NS_ASSUME_NONNULL_BEGIN

@interface CTMediator (ModuleA)

- (BaseViewController *)mediator_ModuleAPage1ViewController:(NSDictionary *)params;

- (BaseViewController *)mediator_ModuleAPage2ViewController:(NSDictionary *)params;

@end

NS_ASSUME_NONNULL_END
#import "CTMediator+ModuleA.h"

//  字符串 是类名 Target_xxx.h 中的 xxx 部分
NSString * const kCTMediatorTarget_ModuleA = @"ModuleA";
//  字符串是 Target_xxx.h 中 定义的 Action_xxxx 函数名的 xxx 部分
NSString * const kCTMediatorActionNativTo_ModuleAPage1ViewController = @"ModuleAPage1ViewController";
NSString * const kCTMediatorActionNativTo_ModuleAPage2ViewController = @"ModuleAPage2ViewController";

@implementation CTMediator (ModuleA)

- (BaseViewController *)mediator_ModuleAPage1ViewController:(NSDictionary *)params{
   BaseViewController *viewController = [self performTarget:kCTMediatorTarget_ModuleA
                                                   action:kCTMediatorActionNativTo_ModuleAPage1ViewController
                                                   params:params shouldCacheTarget:NO];
   if ([viewController isKindOfClass:[UIViewController class]]) {
       // view controller 交付出去之后,可以由外界选择是push还是present
       return viewController;
   } else {
       // 这里处理异常场景,具体如何处理取决于产品
       NSLog(@"%@ 未能实例化页面", NSStringFromSelector(_cmd));
       return [[BaseViewController alloc] init];
   }
}

- (BaseViewController *)mediator_ModuleAPage2ViewController:(NSDictionary *)params{
   BaseViewController *viewController = [self performTarget:kCTMediatorTarget_ModuleA
                                                     action:kCTMediatorActionNativTo_ModuleAPage2ViewController
                                                     params:params shouldCacheTarget:NO];
     if ([viewController isKindOfClass:[UIViewController class]]) {
         // view controller 交付出去之后,可以由外界选择是push还是present
         return viewController;
     } else {
         // 这里处理异常场景,具体如何处理取决于产品
         NSLog(@"%@ 未能实例化页面", NSStringFromSelector(_cmd));
         return [[BaseViewController alloc] init];
     }
}

@end

Target_ModuleA

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Target_ModuleA : NSObject

- (BaseViewController *)Action_ModuleAPage1ViewController:(NSDictionary *)params;

- (BaseViewController *)Action_ModuleAPage2ViewController:(NSDictionary *)params;

@end

NS_ASSUME_NONNULL_END
#import "Target_ModuleA.h"
#import "ModuleAPage1ViewController.h"
#import "ModuleAPage2ViewController.h"

@implementation Target_ModuleA

- (BaseViewController *)Action_ModuleAPage1ViewController:(NSDictionary *)params{
    ModuleAPage1ViewController *vc = [[ModuleAPage1ViewController alloc]init];
    vc.parameter = params;
    return vc;
}

- (BaseViewController *)Action_ModuleAPage2ViewController:(NSDictionary *)params{
    ModuleAPage2ViewController *vc = [[ModuleAPage2ViewController alloc]init];
    vc.parameter = params;
    return vc;
}


@end

ModuleAPage1ViewController

#import "ModuleAPage1ViewController.h"

@interface ModuleAPage1ViewController ()<UITableViewDelegate,UITableViewDataSource>

@property(strong, nonatomic) UITableView *tableView;
@property(strong, nonatomic) NSArray *dataArray;

@end

@implementation ModuleAPage1ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.view.backgroundColor = [UIColor whiteColor];
    [self setupTableView];
    self.dataArray = @[@"ModuleAPage2",@"ModuleBPage1",@"ModuleCPage1"];
    [self.tableView reloadData];
}

- (void)setupTableView{
    self.tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view addSubview:self.tableView];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIndetifier = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndetifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndetifier];
    }
    cell.textLabel.text = self.dataArray[indexPath.row];
    return cell;;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 44.f;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    switch (indexPath.row) {
        case 0:
            [self pushModuleAPage2];
            break;
        case 1:
            [self pushModuleBPage1];
            break;
        case 2:
            [self presentModuleCPage1];
            break;
            
        default:
            break;
    }
    
}

- (void)pushModuleAPage2
{
    UIViewController *viewController = [[CTMediator sharedInstance] mediator_ModuleAPage2ViewController:@{@"page":@"ModuleAPage1"}];
     [viewController setHidesBottomBarWhenPushed:YES];
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)pushModuleBPage1
{
     UIViewController *viewController = [[CTMediator sharedInstance] mediator_ModuleBPage1ViewController];
     [viewController setHidesBottomBarWhenPushed:YES];
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)presentModuleCPage1
{
     UIViewController *viewController = [[CTMediator sharedInstance] mediator_ModuleCPage1ViewController];
    [self.navigationController presentViewController:viewController animated:NO completion:nil];
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

只粘贴一部分代码,其余可以看Demo,

从ModuleAPage1ViewController中代码可看出跳转部分都没有#import Module 这就是我们说的说的组件化。传统方式是我们需要跳转那个页面,就需要#import相关的页面,但是使用了CTMediator之后我们只要知道这个页面是属于那个Module,或者说属于那个组件,然后直接调用相关的组件即可。

组件化的优点

举个例子,公司某个App有一个登录模块,过一段时间需要研发一个新的App,为了节省时间就用之前App有的登录模块,就需要把登录模块抽取出来做成组件,可能某些同学就会问,这不是私有化Pod库就能实现吗?

接着说即使把登录模块私有化Pod后,那么假如在B项目中ModuleA,ModuleB,ModuleC都需要验证,如果没有登录就调用登录模块,哪又回到了之前耦合的问题上了ModuleA,ModuleB,ModuleC都需要#import 登录模块,所以私有化只是组件的一部分。只有实现组件化才能解耦。

怎么判断项目需要组件化

1.需要组件化首先就需要模块化,就是对业务的高度抽象。需要把相关的业务都抽取到一个模块里面。这就不适合创业公司或者只有一个开发人员的公司。小公司和创业公司基本都是在试错,业务基本不稳定。高度抽象业务很难。如果在创业公司项目因业务不稳定,也不建议使用组件化。

2.公司如果只有一个开发人员也不建议使用组件化,组件化最大难度就是高度抽取业务,抽取出来组件化也需要维护,像我们公司一个人开发维护2个App哪就不要给自己找罪受了。

3.如果公司有2个以上开发人员并且时间相对充裕的情况下,在公司业务相对稳定,的情况下可以考虑使用组件化。

4.公司有2个及以上App,有重合的业务可以优先考虑先把重合业务抽取成组件。

以上仅代表个人观点,具体项目中需不需组件化还是要看自己,自己想怎么用就怎么用。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件化的优点
  • 怎么判断项目需要组件化
  • 以上仅代表个人观点,具体项目中需不需组件化还是要看自己,自己想怎么用就怎么用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档