对于路由方案业界通常有三种方案:
1,Url-scheme注册(MGJRouter),我感觉适用于后端下发数据跳转,但是组件之间调用如果还拼接Url感觉徒增复杂度
2,利用Runtime实现的target-action方式(CTMediator),优点是及其灵活知道类名和方法名字就可以跳转,在实际应用时为了避免字符串满天飞还需要写个桥接的方法进行二次封装,略微繁琐.优点:灵活完全解耦.
3,protcol-class,通过协议拿到对应的子模块实现对象,然后进行调用,和2比优点:不需要写具体的桥接实现.缺点:不如2灵活需要依赖具体的协议文件可以通过子pod来解决
通过比较我认为路由需要分为两个方面考虑:1:子模块之间相互调用.2后端或者h5下发字符串进行调用.
对于解决第一个问题,我采用protocol-class方案,具体调用如下:
对于KCHomePageProtocol和KCHomePageImplement的映射逻辑长用的是对名字进行特定的约定:前缀都是KCHomePage,后缀都是Protocol和Implement,
另一种是调用注册api
let keyName = String(describing: KaoChongProtocol.self)//主工程需要这种方案
ModuleManager.register(obj: KaoChongImplement(), forKey: keyName)
//子模块具体操作
public class KCHomePageImplement: NSObject, KCHomePageProtocol{
public func goHomeVc() {
print("goHome")
}
}
//协议层调用
public extension ModuleManager{
static func getHomePageModule() -> KCHomePageProtocol?{
let keyName = String(describing: KCHomePageProtocol.self)
return ModuleManager.get(key: keyName) as? KCHomePageProtocol
}
}
//具体协议接口,可以放在一个字pod,供其他业务放调用
public protocol KCHomePageProtocol:ModuleProtocol{
func goHomeVc()
}
ModuleManager.getHomePageModule()?.goHomeVc()
对于解决第二个问题,我采用url-block的方案,对于解决注册所产生的load耗时问题,我采用attribute写入到math-0文件的_data字段进行存储,在第一次调用openActionUrl的时候进行懒加载调用registerRouter方法进行注册
public class KCHomePageImplement: NSObject,FRouterProtocol {
//代替load方法进行注册
public func registerRouter() {
FRouter.manager.register(name: "goHome") { (params) in
print("goHome ---- \(params)")
let vc = KCHomeVc()
ModuleManager.topViewController?.navigationController?.pushViewController(vc, animated: true)
}
}
}
//需要创建一个oc文件写入注册api,子模块名,和实现FRouterProtocol协议的桥接类
@FService(KCHomePageModule,KCHomePageImplement)
//外接调用
FRouter.openActionUrl(url: "{\"name\":\"goHome\",\"response\":\"response\",\"extra\":{\"orderId\":\"123\"}}")
//对于url-block的路由原来的attribute注册有个问题需要写单独写一个oc文件进行注册,比较麻烦,最近学习到一个新的方案,根据分类方法copy覆盖的逻辑,通过下面代码可以拿到响应分类的所有method,然后在分别调用,这样在子模块就可以通过分类方法的方式进行注册,避免了写oc文件的尴尬.
//Modukit模块
+ (void)runTests
{
unsigned int count;
Method *methods = class_copyMethodList([FRouter class], &count);
for (int i = 0; i < count; i++)
{
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
if ([name hasPrefix:@"newRegister"]) {
text_method_t textImp = method_getImplementation(method);
(*textImp)(FRouter.manager, selector);
}
}
}
//子模块
extension FRouter {
@objc func newRegister() {
print("home - text")
}
}
详情见demo
https://github.com/riceForChina/FMiddleLevel.git