淺談iOS元件化
背景:隨著應用不停得進行版本迭代、功能模組的逐步增加,使得應用的程式碼體積越來越大,業務和功能間的依賴關係越來越複雜,耦合度越來越高,嚴重得降低了業務方的開發效率。在此背景下,元件化開發的思路得以進入眾多app開發架構的設計方案之中。
簡介:元件化開發的方案是將app分成了多個元件進行開發,各個元件之間可以互相通訊,但是元件之間不能有直接的約束、不能直接引用。
實現方式:1 URL--Block方式;2 Target--Action方式。
1 URL-Block方式
蘑菇街App採用的元件化模式,每次啟動時需要例項化各個模組的元件,並且通過URL註冊響應者,每次註冊時會將URL作為一個key值,與對應的Block儲存在本地的登錄檔之中。元件管理器就是通過本地儲存的這張登錄檔去知道有哪些模組哪些介面,介面的形式就是URL-Block。
[MGJRouter registerURLPattern:@"mgj://cart/ordercount" toObjectHandler:^id(NSDictionary *routerParamters){
// do some calculation
return @42;
}]
NSNumber *orderCount = [MGJRouter objectForURL:@"mgj://cart/ordercount”]
缺點:(1)採用key-block形式需要記憶體維護一張登錄檔,造成不必要的記憶體常駐。
(2)沒有區分遠端呼叫和本地呼叫。
2 Target-Action方式
每個元件都通過Action暴露可呼叫介面,元件通過自帶得Target-Action來響應。
[[CTMediator sharedInstance] performTarget:targetName action:actionName params:@{…}]
根據targetName和actionName,可以通過Runtime機制轉化生成Target的例項以及Action的選擇子
NSString *targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
Class targetClass = NSClassFromString(targetClassString);
id target = [[targetClass alloc] init];
SEL action = NSSelectorFromString(actionString);
最後通過獲得例項物件及選擇子呼叫目標業務邏輯。
[target performSelector:action withObjects:params];
同時Target-Action的方式中區分了遠端呼叫和本地呼叫,由本地呼叫服務為遠端呼叫提供服務
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
return [[[CTMediator sharedInstance] performActionWithUrl:url completion:nil] boolValue];
}
由於遠端呼叫只能通過jsonString的形式來提供複雜引數,所以我們在遠端呼叫時只能將非常規的引數轉化成jsonString再通過urlEncode後,通過GET的形式來提供複雜引數。在openURL方法中接收到url後,要對url進行解析得到我們想要的引數才能呼叫本地呼叫的服務。結論:遠端呼叫比本地呼叫多了一個解析URL的過程,因此遠端呼叫和本地呼叫必須拆開,不能走同一個介面。- (id)performActionWithUrl:(NSURL *)url completion:(void (^)(NSDictionary *))completion
{
/*
....(在此對url進行解析,並且得到targetName和actionName以及params)
*/
//然後再走本地呼叫的介面
id result = [self performTarget:targetName action:actionName params:params];
return result;
}使用category定製不同元件的中介軟體
因為呼叫方不知道將要調起的元件需要傳遞哪些引數、以及哪些target可以呼叫,所以可以使用category的優勢來針對每個元件寫一個有針對性的中介軟體的類別。
//CTMediator+CTMediatorModuleAActions.m
- (void)CTMediator_presentImage:(UIImage *)image
{
if (image) {
[self performTarget:kCTMediatorTargetA
action:kCTMediatorActionNativePresentImage
params:@{@"image":image}];
} else {
// 這裡處理image為nil的場景,如何處理取決於產品
[self performTarget:kCTMediatorTargetA
action:kCTMediatorActionNativeNoImage
params:@{@"image":[UIImage imageNamed:@"noImage"]}];
}
}
這樣做得好處:(1)在category的方法中可以做引數驗證,例如上面的方法中,接收的引數為image物件,就可以校驗呼叫方傳的引數是否為image。是image的話在category方法中將其封裝再走本地呼叫元件的方法。
(2)category統一了元件呼叫入口,因此無論在除錯還是在原始碼閱讀上都為開發者提供了極大的便利。
(3)由於category統一了元件呼叫入口,因此可以在category中使用巨集或者呼叫宣告。
(4)使用category可以解決元件間呼叫去Model化帶來的引數繁雜的問題。
拆分元件
(1)基礎功能元件
(2)基礎UI元件
(3)產品業務元件
總結:元件化適用於業務穩定、邏輯複雜的app,能夠解決專案模組間得耦合問題,有助於多人大團隊的協同開發。方便元件的單獨開發、單獨測試。
參考文章:
http://www.th7.cn/Program/IOS/201603/776240.shtml
http://www.tuicool.com/articles/AB7jqeY
http://www.jianshu.com/p/afb9b52143d4