在模組化的過程當中,業務模塊間的通訊每每是處理最多的.與其應運而生的解決方案有如下幾種:html
Runtime
動態發現服務前輩們在借鑑 web 服務路由設計以後,將服務綁定至固定規則的 URL 上.nginx
Target-Action
形式設計的路由組件.什麼是 Target-Action?git
ans: 目標-行爲模式,它貫穿於iOS開發始終, 最多見的即是:github
UIButton().addTarget(target: target, action: action, for: event)
複製代碼
什麼是 Target-Action 形式的路由?web
ans: 在觸發路由路徑時, 經過 Runtime
機制來發現具體服務,並執行.objective-c
相對於提早統一註冊的路由,至關於懶加載.swift
NSObject
: Runtime
機制自己即是基於 NSObject
.@objc(ClassName)
: 因爲Xcode 8.0以後在編譯時會移除未顯式使用的swift類與函數,因此須要加此聲明.(服務類不建議在任何模塊實例化,會破壞設計邏輯)@objcMembers
: 在swift 4.0
中繼承 NSObject
的 swift class
再也不默認所有橋接到 objective-c
,若是咱們想要使用的話咱們就須要在class前面加上 @objcMembers
這麼一個關鍵字.@objc(AModule) @objcMembers
class AModule: NSObject { }
複製代碼
參數類型限制: 只能使用單個KhalaInfo(集合類型)
與多個 KhalaClosure(閉包類型)
緩存
第一個參數須要匿名: 方便查找函數, 非匿名swift
函數橋接至 objective-c
時會造成funNameWithParam
結構.(Khala
前期在此花費時間較多, 最後仍是採用該折中方案.)閉包
示例以下以下:架構
@objc(AModule) @objcMembers
class AModule: NSObject,UIApplicationDelegate {
func vc() -> UIViewController {
let vc = UIViewController()
vc.view.backgroundColor = UIColor.red
return vc
}
func action(_ info: KhalaInfo, success: KhalaClosure, failure: KhalaClosure) {
success(["success": #function])
failure(["failure": #function])
}
}
複製代碼
通用型調用
Khala(str: "kf://AModule/forClosures")?.call(blocks: { (item) in
print("forClosures block3:", item)
},{ (item) in
print("forClosure block4:", item)
})
let value = Khala(str: "kl://AModule/doSomething")?.call()
複製代碼
UIKit
特例化調用:
guard let vc = Khala(str: "kl://BModule/vc?style=0")?.viewController else { return }
self.navigationController?.pushViewController(vc, animated: true)
複製代碼
該部分設計來源自nginx: 在某些場景下須要對 URL 進行轉化與攔截, 例如:
服務類與服務函數存在前綴.
接收非標準 URL .
URL重定向: 頁面的動態升降級, 示例以下:
let filter = KhalaRewriteFilter {
if $0.url.host == "AModule" {
var urlComponents = URLComponents(url: $0.url, resolvingAgainstBaseURL: true)!
urlComponents.host = "BModule"
$0.url = urlComponents.url!
}
return $0
}
Khala.rewrite.add(filter: filter)
// "kl://AModule/doSomething" => "kl://BModule/doSomething"
let value = Khala(str: "kl://AModule/doSomething")?.call()
print(value ?? "nil")
複製代碼
部分組件每每依賴於主工程中的AppDelegate
中部分函數.
Khala
中,須要顯式的在主工程中的AppDelegate
調用與處理相關邏輯.UIApplicationDelegate
協議.主工程AppDelegate
:
@UIApplicationMain
class AppDelegate: UIResponder,UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let list = Khala.appDelegate.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
}
複製代碼
組件中服務類:
@objc(AModule) @objcMembers
class AModule: NSObject,UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("AModule.didFinishLaunchingWithOptions")
return true
}
}
複製代碼
每一份url請求都將記錄至日誌文件中, 能夠在適當的時候提供開發者便利.
開啓日誌(默認關閉)
Khala.isEnabledLog = true
// or
Khala.history.isEnabled = true
複製代碼
文件路徑: /Documents/khala/logs/
文件內容: 日期 + 時間 + URL + 參數
2018-12-01 02:06:54 kl://SwiftClass/double? {"test":"666"}
2018-12-01 02:06:54 kl://SwiftClass/double {"test":"666"}
複製代碼
khala 庫中提供了一個空置的類[KhalaStore]用於盛放路由函數對應的本地函數.來簡化本地調用複雜度的問題.
extension KhalaStore {
class func aModule_server(value: Int) -> Int {
return Khala(str: "kf://AModule/server", params: ["value": value])!.call() as! Int
}
}
@objc(AModule) @objcMembers
class AModule: NSObject {
func server(_ info: [String: Any]) -> Int {
return info["value"] as? Int ?? 0
}
}
let value = KhalaStore.aModule_server(value: 46)
複製代碼
ps: KhalaStore 擴展文件建議統一放置.
爲方便開發者使用,添加了部分場景下斷言機制,示例:
khala.iOS Fatal error: [Khala] 未在[AModule]中匹配到函數[server], 請查看函數列表:
0: init
1: doSomething:
2: vc
複製代碼
關閉斷言(默認開啓):
Khala.isEnabledAssert = false
複製代碼
當路由第一次調用/註冊路由類時,該路由類將被緩存至 KhalaClass.cache 中, 以提升二次查找性能.
當路由類實例化時,該路由類中的函數列表將被緩存至 KhalaClass().methodLists中, 以提升查找性能.
僅供參考, 合適纔是最好的.
Marmot-iOS: 基於 Khala 設計的 hybird(WKWebview
<=> Native
) 通訊組件.