组件化方案的对比和分析

本文将介绍下主流的三种组件化方案,并对比分析各自的优缺点。

Target Action

主要思路

  • 抽离业务逻辑
  • 通过中间层进行调用
  • 中间层使用Runtime反射

缺点

  • 硬编码
  • 中间层容易臃肿<可以用分类做拆分>
  • performSelector 方法传参有限

代码实现

.h文件

1
2
3
4
5
6
7
8


@interface BPMediator : NSObject

// Target Action
+ (__kindof UIViewController *)twoViewControllerWithParam:(NSString *)param;

@end

.m文件

1
2
3
4
5
6
7
8
9
10
11
@implementation BPMediator

+ (__kindof UIViewController *)twoViewControllerWithParam:(NSString *)param {

Class twoCls = NSClassFromString(@"TwoViewController");
UIViewController *controller = [[twoCls alloc] performSelector:NSSelectorFromString(@"initWithParam:") withObject:param];
return controller;

}

@end

调用<控制器1>

1
[self.navigationController pushViewController:[BPMediator twoViewControllerWithParam:@"Target Action"] animated:YES];

URL Scheme

主要思路

  • 使用URL处理本地的跳转
  • 通过中间层进行注册和调用
  • 注册表无需使用反射

缺点

  • 具体参数不透明
  • 非懒加载
  • 注册表的维护

代码实现

.h文件

1
2
3
4
5
6
7
8
9
10


@interface BPMediator : NSObject

typedef void(^BPMediatorProgressBlock)(NSDictionary *param);

+ (void)registerScheme:(NSString *)scheme processBlock:(BPMediatorProgressBlock)processBlock;
+ (void)openUrl:(NSString *)url params:(NSString *)params;

@end

.m文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

@implementation BPMediator

+ (NSMutableDictionary *)mediatorCache {
static NSMutableDictionary *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [NSMutableDictionary dictionary];
});
return cache;
}

+ (void)registerScheme:(NSString *)scheme processBlock:(BPMediatorProgressBlock)processBlock {
if (scheme && processBlock) {
[[[self class] mediatorCache] setObject:processBlock forKey:scheme];
}
}

+ (void)openUrl:(NSString *)url params:(NSDictionary *)params {

/**
url 可携带额外参数 此时取scheme作为key 当前简便实用url为key
*/
BPMediatorProgressBlock block = [[[self class] mediatorCache] objectForKey:url];
if (block) {
block(params);
}
}

@end

注册URL<控制器2>

1
2
3
4
5
6
7
8
9
10
+ (void)load {
// URL Scheme
[BPMediator registerScheme:@"twoController://" processBlock:^(NSDictionary * _Nonnull params) {
NSString *param = [params objectForKey:@"param"];
UINavigationController *nav = (UINavigationController *)[params objectForKey:@"controller"];
TwoViewController *controller = [[TwoViewController alloc] initWithParam:param];
[nav pushViewController:controller animated:YES];
}];

}

调用URL<控制器1>

1
2

[BPMediator openUrl:@"twoController://" params:@{@"controller":self.navigationController,@"param":@"URL Scheme"}];

Protocol Class

主要思路

  • 增加 Protocol Wrapper 层
  • 中间件返回 Protocol 对应的 Class
  • 解决硬编码的问题

缺点

同URL Scheme

代码实现

.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14

@protocol BPTwoViewControllerProtocol <NSObject>

- (__kindof UIViewController *)twoViewControllerWithParam:(NSString *)param;

@end

@interface BPMediator : NSObject

// Protocol Class
+ (void)registerProtocol:(Protocol *)protocol cls:(Class)cls;
+ (Class)classForProtocol:(Protocol *)protocol;

@end

.m文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

@implementation BPMediator

+ (NSMutableDictionary *)mediatorCache {
static NSMutableDictionary *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [NSMutableDictionary dictionary];
});
return cache;
}

+ (void)registerProtocol:(Protocol *) protocol cls:(Class)cls {
if (protocol && cls) {
[[[self class] mediatorCache] setObject:cls forKey:NSStringFromProtocol(protocol)];
}
}

+ (Class)classForProtocol:(Protocol *) protocol {
return [[[self class] mediatorCache] objectForKey:NSStringFromProtocol(protocol)];
}


@end

遵守、实现、注册Protocol <控制器2>

1
2
3
4
5
6
7
8
9
10
+ (void)load {
// Protocol Class
[BPMediator registerProtocol:@protocol(BPTwoViewControllerProtocol) cls:[self class]];

}

// BPTwoViewControllerProtocol
- (__kindof UIViewController *)twoViewControllerWithParam:(NSString *)param {
return [self initWithParam:param];
}

调用Protocol <控制器1>

1
2
3
4

Class cls = [BPMediator classForProtocol:@protocol(BPTwoViewControllerProtocol)];

[self.navigationController pushViewController:[[cls alloc] twoViewControllerWithParam:@"Protocol Class"] animated:YES];

总结

Demo传送门

这三种方案各有优劣。

在实际的开发中,结合当前的业务情况,有可能采用多种方案。要根据当前的需求细节和团队开发能力,选择合适的方案。