一、介紹
組件化這件事溯捆,簡(jiǎn)單理解就是把不同的業(yè)務(wù)拆分成單獨(dú)的項(xiàng)目去開(kāi)發(fā),組件之間可以出現(xiàn)引用關(guān)系厦瓢,但不可以出現(xiàn)依賴(lài)關(guān)系提揍。
由于組件是不可以依賴(lài)另一個(gè)組件的,這導(dǎo)致調(diào)用其他組件的對(duì)外接口
成為了一件很麻煩的事煮仇,傳統(tǒng)方案是使用字符串
映射Selector
劳跃,這種方案依賴(lài)字符串
這個(gè)不穩(wěn)定的Key,不但沒(méi)有代碼聯(lián)想浙垫,還會(huì)導(dǎo)致很多難以預(yù)測(cè)的問(wèn)題刨仑。
經(jīng)過(guò)一些嘗試,我發(fā)現(xiàn)了還有一種簡(jiǎn)單的方案夹姥。TKModule
作為組件的中間件杉武,各組件可以通過(guò)創(chuàng)建TKModule
的分類(lèi)實(shí)現(xiàn)對(duì)外接口
,也通過(guò)TKModule
去調(diào)用其他組件的對(duì)外接口
辙售。
當(dāng)然轻抱,這也會(huì)帶來(lái)一些問(wèn)題:
- 我在開(kāi)發(fā)A組件的時(shí)候,不能依賴(lài)B組件旦部,那么我的開(kāi)發(fā)環(huán)境中就不存在B組件的
對(duì)外接口
祈搜,就沒(méi)法去調(diào)用较店。
- 解決方案:組件間不可以依賴(lài),但是可以引用容燕。如果B組件的
對(duì)外接口
已經(jīng)聲明梁呈、實(shí)現(xiàn)并發(fā)布,我可以在A組件的Demo的Podfile添加B組件缰趋。
- 我在開(kāi)發(fā)A組件的時(shí)候捧杉,C組件的
對(duì)外接口
僅僅作出聲明陕见,尚未實(shí)現(xiàn)便發(fā)布了秘血,這時(shí)在A組件中調(diào)用C組件的對(duì)外接口
便會(huì)導(dǎo)致崩潰。
- 解決方案: 在
TKModule
替換
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector;
- (void)forwardInvocation:(NSInvocation *)invocation;
的實(shí)現(xiàn)评甜,使用戶(hù)(組件使用者)調(diào)用未實(shí)現(xiàn)的接口時(shí)會(huì)執(zhí)行一個(gè)空的實(shí)現(xiàn)灰粮,避免崩潰。
此外忍坷,我也可以在A組件的Demo中粘舟,根據(jù)我的需要去實(shí)現(xiàn)這個(gè)接口。
- 我在開(kāi)發(fā)A組件的時(shí)候佩研,D組件尚發(fā)布柑肴,這時(shí)在A組件中如何調(diào)用D組件的接口。
- 解決方案:遇到種情況我們可以在A組件中去聲明想要引用的接口旬薯。
二晰骑、基礎(chǔ)用法
-
實(shí)現(xiàn)接口
// TKModule+Account.h
// TKMAccountModule
@interface TKModule (Account)
- (void)showLoginView;
@end
// TKModule+Account.m
// TKMAccountModule
@implementation TKModule (Account)
- (void)showLoginView {
//展示登錄界面
}
-
調(diào)用接口
// TKMInitializeEntrance.m
// TKMInitializeModule
#import "TKMInitializeEntrance.h"
@implementation TKMInitializeEntrance
...
- (void)loginButtonTapped {
[[TKModule shared] showLoginView];
}
...
@end
三、補(bǔ)充用法
-
在組件中聲明其他組件的對(duì)外接口
// TKModule+AccountRecharge.h
// TKMAccountModule
#import "TKModule.h"
@interface TKModule (AccountRecharge)
- (void)showRechargeView;
@end
-
在Demo中實(shí)現(xiàn)其他組件的對(duì)外接口
// TKModule+Mock.m
// TKMAccountModule-Example
#import <TKModule/TKModule.h>
@implementation TKModule (Mock)
- (void)showRechargeView {
//展示充值頁(yè)面
}
@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