在iOS開發過程當中,隨着項目的愈來愈龐大,一些基礎組件須要單獨剝離出來。單獨剝離出來的基礎組件也會由於業務需求的不斷變化而愈來愈臃腫難以維護。如何去解決這個問題,插件化的設計能夠爲你們提供一些思路。接下來我將以webView的插件設計爲例。web
在成熟的項目中每每會採用封裝好一個webView,複用於各個須要的地方。好處天然不言而喻,減小了冗餘代碼,統一規範,易於維護等。app
同時,webView每每須要和H5頁面進行交互,交互的實現方式多種多樣,在此不表。隨着項目規模愈來愈大,針對不一樣的業務需求,每每須要在webView中添加各類各樣的交互邏輯,最後就致使webView愈來愈臃腫愈來愈難以維護。ui
爲此,設計一套插件化的實現,來解決這個問題。 經過插件來賦予webView各類各樣的能力,同時插件與webView解耦,結構上更易於維護和易懂。spa
這裏以webView和H5的交互爲例。創造出來的每一個插件都對應一個Action。在H5將事件拋給webView的時候,webView將事件交給對應的插件去完成。插件
在此流程上,有兩個須要關注的點。設計
到此,咱們須要分析插件的設計要求。code
對此,咱們能夠準備一個插件基類:webViewPlugin
cdn
/* 插件查詢表 */
static NSMutableDictionary<NSString *, NSString *> *pluginsMapping;
+ (NSString *)actionName {
return @"";
}
+ (void)registerPlugin {
if (pluginsMapping == nil) {
pluginsMapping = [NSMutableDictionary<NSString *, NSString *> dictionary];
}
[pluginsMapping setObject:NSStringFromClass(self) forKey:[self actionName]];
}
- (nullable __kindof instancetype)initWithHandlerName:(NSString *)handlerName
parameters:(NSDictionary<NSString *, id> *)parameters
forWebView:(webView *)webView {
NSString *className = [pluginsMapping objectForKey:handlerName];
Class clazz = NSClassFromString(className);
if (clazz == nil || ![clazz isSubclassOfClass:WebViewPlugin.class]) {
return nil;
}
WebViewPlugin *plugin = [[clazz alloc] init];
plugin.handlerName = handlerName;
plugin.parameters = parameters;
plugin.webView = webView;
return plugin;
}
- (void)startAction {
}
複製代碼
基類中準備了4個方法:blog
一個是對應的Action的名稱,其實也能夠理解爲每一個Plugin對應的key,在webView接收到事件之後,咱們須要經過這個Key來查找對應的Plugin。繼承
第二個是註冊方法,在這裏能夠看到我準備了一個靜態的Dictionary,使用靜態的Dictionary是由於這個字典能夠單獨存儲在靜態區,方便隨取隨用。
第三個就是對應的初始化方法。初始化方法中主要作的事情就是從存儲好的註冊表里根據外部傳進來的key將對應的plugin初始化。
第四個就是plugin須要實現的Action。
到此Plugin的基類就完成了。經過繼承並實現對應的方法來添加Plugin。
如WebViewPluginClose
,那它的實現就是:
+ (void)load {
[self registerPlugin];
}
+ (NSString *)actionName {
return @"close_webview";
}
- (void)startAction {
[self.webView removeFromSuperview];
}
複製代碼
在子類的實現中,我將插件的註冊方法寫在了load
方法中。 load
方法是項目代碼加載之後每一個類都會調用的方法,而且父類先於子類。 因此在此添加註冊方法免去了上層業務手動註冊管理等操做。 同時實現了actionName
也就是定義了對應的key,最後將操做放在了startAction
中。
在webView接收到事件後,根據對應的Key去分發給相應的插件:
WebViewPlugin *plugin = [[WebViewPlugin alloc] initWithHandlerName:name parameters:params forWebView:self];
[plugin startAction];
複製代碼
在此例子的基礎上還能夠根據業務的需求完善更多的設計。好比將消息數據統一分發給一個PluginManager,在PluginManager中又能夠作消息轉發數據預處理等等知足更復雜的場景需求。每一個插件也能夠根據須要賦予不一樣的能力,甚至規劃更多類型的插件。
在此筆者藉助webView的例子想向和你們分享的是插件化的這一設計思路。這樣的設計思路不單單適用於webView等,一樣也能夠給UIView的組件或某個Controller等使用。在實現業務解藕的同時也讓代碼更加易於維護。