一、介绍
组件化这件事,简单理解就是把不同的业务拆分成单独的项目去开发,组件之间可以出现引用关系,但不可以出现依赖关系。
由于组件是不可以依赖另一个组件的,这导致调用其他组件的对外接口
成为了一件很麻烦的事,传统方案是使用字符串
映射Selector
,这种方案依赖字符串
这个不稳定的Key,不但没有代码联想,还会导致很多难以预测的问题。
经过一些尝试,我发现了还有一种简单的方案。TKModule
作为组件的中间件,各组件可以通过创建TKModule
的分类实现对外接口
,也通过TKModule
去调用其他组件的对外接口
。
当然,这也会带来一些问题:
- 我在开发A组件的时候,不能依赖B组件,那么我的开发环境中就不存在B组件的
对外接口
,就没法去调用。
- 解决方案:组件间不可以依赖,但是可以引用。如果B组件的
对外接口
已经声明、实现并发布,我可以在A组件的Demo的Podfile添加B组件。
- 我在开发A组件的时候,C组件的
对外接口
仅仅作出声明,尚未实现便发布了,这时在A组件中调用C组件的对外接口
便会导致崩溃。
- 解决方案: 在
TKModule
替换
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector;
- (void)forwardInvocation:(NSInvocation *)invocation;
的实现,使用户(组件使用者)调用未实现的接口时会执行一个空的实现,避免崩溃。
此外,我也可以在A组件的Demo中,根据我的需要去实现这个接口。
- 我在开发A组件的时候,D组件尚发布,这时在A组件中如何调用D组件的接口。
- 解决方案:遇到种情况我们可以在A组件中去声明想要引用的接口。
二、基础用法
-
实现接口
// TKModule+Account.h
// TKMAccountModule
@interface TKModule (Account)
- (void)showLoginView;
@end
// TKModule+Account.m
// TKMAccountModule
@implementation TKModule (Account)
- (void)showLoginView {
//展示登录界面
}
-
调用接口
// TKMInitializeEntrance.m
// TKMInitializeModule
#import "TKMInitializeEntrance.h"
@implementation TKMInitializeEntrance
...
- (void)loginButtonTapped {
[[TKModule shared] showLoginView];
}
...
@end
三、补充用法
-
在组件中声明其他组件的对外接口
// TKModule+AccountRecharge.h
// TKMAccountModule
#import "TKModule.h"
@interface TKModule (AccountRecharge)
- (void)showRechargeView;
@end
-
在Demo中实现其他组件的对外接口
// TKModule+Mock.m
// TKMAccountModule-Example
#import <TKModule/TKModule.h>
@implementation TKModule (Mock)
- (void)showRechargeView {
//展示充值页面
}
@end
四、代码
// TKModule.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^TKModuleUnrecognizedSelectorCallback)(SEL);
@interface TKModule : NSObject
@property (nonatomic, strong) TKModuleUnrecognizedSelectorCallback unrecognizedSelectorCallback;
+ (instancetype)shared;
@end
NS_ASSUME_NONNULL_END
// TKModule.m
#import "TKModule.h"
#import <objc/runtime.h>
@implementation TKModule
#pragma mark - shared
+ (instancetype)shared {
static id instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
#pragma mark - Unrecognized
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
if (!signature) {
if (self.unrecognizedSelectorCallback) self.unrecognizedSelectorCallback(selector);
signature = self.voidSignature;
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if (![invocation.methodSignature isEqual:self.voidSignature]) {
[super forwardInvocation:invocation];
}
}
#pragma mark - util
- (NSMethodSignature *)voidSignature {
return [self methodSignatureForSelector:@selector(unrecognizedSelectorBackUp)];
}
- (void)unrecognizedSelectorBackUp {
}
@end
网友评论