在模组化的过程当中,业务模块间的通讯每每是处理最多的.与其应运而生的解决方案有如下几种: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
) 通讯组件.