Khala路由組件介紹與使用

前言

在模組化的過程中,業務模塊間的通信往往是處理最多的.與其應運而生的解決方案有以下幾種:

  1. 提前註冊服務
  2. Runtime 動態發現服務

前輩們在借鑑 web 服務路由設計之後,將服務綁定至固定規則的 URL 上.

  1. CTMediator: Target-Action 形式設計的路由組件.
  2. 其他以統一註冊形式設計的路由.

前情提要

什麼是 Target-Action?

ans: 目標-行爲模式,它貫穿於iOS開發始終, 最常見的便是:

UIButton().addTarget(target: target, action: action, for: event)    

什麼是 Target-Action 形式的路由?

ans: 在觸發路由路徑時, 通過 Runtime機制來發現具體服務,並執行.

相對於提前統一註冊的路由,相當於懶加載.

Khala 路由組件使用

一. 編寫 服務類(路由類)

  1. 繼承自NSObject: Runtime機制本身便是基於 NSObject.
  2. 聲明@objc(ClassName): 由於Xcode 8.0之後在編譯時會移除未顯式使用的swift類與函數,所以需要加此聲明.(服務類不建議在任何模塊實例化,會破壞設計邏輯)
  3. 聲明@objcMembers: 在swift 4.0 中繼承 NSObjectswift class 不再默認全部橋接到 objective-c,如果我們想要使用的話我們就需要在class前面加上 @objcMembers 這麼一個關鍵字.
  4. 示例如下如下:
@objc(AModule) @objcMembers
class AModule: NSObject { }

二. 編寫 服務函數(路由函數)

  1. 參數類型限制: 只能使用單個KhalaInfo(集合類型)與多個 KhalaClosure(閉包類型)

  2. 第一個參數需要匿名: 方便查找函數, 非匿名swift函數橋接至 objective-c時會形成funNameWithParam結構.(Khala前期在此花費時間較多, 最後還是採用該折中方案.)

  3. 示例如下如下:

    @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])
      }
        
    }
    

三. 調用

  1. 通用型調用

     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()
    
  2. UIKit特例化調用:

    guard let vc = Khala(str: "kl://BModule/vc?style=0")?.viewController else { return }
    self.navigationController?.pushViewController(vc, animated: true)
    

四. URL重寫 (KhalaRewrite)

該部分設計來源自nginx: 在某些場景下需要對 URL 進行轉化與攔截, 例如:

  1. 服務類與服務函數存在前綴.

  2. 接收非標準 URL .

  3. 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")
    

五. UIApplicationDelegate 生命週期分發

部分組件往往依賴於主工程中的AppDelegate中部分函數.

  1. Khala中,需要顯式的在主工程中的AppDelegate調用與處理相關邏輯.
  2. 服務類需要遵守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
  }
  
}

六. 日誌模塊: KhalaHistory

每一份url請求都將記錄至日誌文件中, 可以在適當的時候提供開發者便利.

  1. 開啓日誌(默認關閉)

    Khala.isEnabledLog = true
    // or 
    Khala.history.isEnabled = true
    
  2. 文件路徑: /Documents/khala/logs/

  3. 文件內容: 日期 + 時間 + URL + 參數

2018-12-01 02:06:54  kl://SwiftClass/double?  {"test":"666"}
2018-12-01 02:06:54  kl://SwiftClass/double  {"test":"666"}

七. 擴展機制: KhalaStore

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.cache 中, 以提高二次查找性能.

  • 當路由類實例化時,該路由類中的函數列表將被緩存至 KhalaClass().methodLists中, 以提高查找性能.

十. 本司基於路由實現的業務架構

僅供參考, 合適纔是最好的.

相關鏈接

Marmot-iOS: 基於 Khala 設計的 hybird(WKWebview <=> Native ) 通信組件.

參考

蘋果核 - 解耦神器 —— 統跳協議和Rewrite引擎.

蘑菇街路由組件: MGJRouter / 阿里開源組件化方案: BeeHive

casa: iOS應用架構談 組件化方案

bang: iOS 組件化方案探索

linhey: iOS 模組化設計方案

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章