iOS 源码分析(一):CTMediator

简介: iOS 源码分析(一):CTMediator

本文的主要目的是分析CTMediator以及其使用


CTMediator简介


CTMediatorcasatwy开源的一个三方组件通讯框架,下图是通过CTMediator通讯的整体架构图示

image.png

优点:


  • 组件仅通过Action暴露可调用接口,模块与模块之间的接口被固化在了Target-Action这一层,避免了实施组件化的改造过程中,对Business的侵入,同时也提高了组件化接口的可维护性。
  • 方便传递各种类型的参数。
  • 本地组件通讯为远程组件通讯提供服务
  • 利用 category 可以明确声明的接口,进行编译检查
  • 实现方式属于轻量级


缺点:


  • 需要给每一个模块创建对应的 target和 mediator 分类,模块化代码时较为繁琐
  • 在 category 中仍然使用了字符串硬编码,内部使用字典传参
  • 无法保证所调用的目标模块一定存在,运行时才能发现错误


CTMediator原理


解耦原理


  • 通过中介模式,将CTMediator类作为各个模块的中心,各个模块以CTMediator分类的形式扩展功能,CTMediator分类中提供服务
  • 分类中的函数具体去调用target-action,target和action需要以字符串硬编码的形式,如果模块比较多,提供服务比较多,那么字符串的硬编码需要时间维护。
  • 去model化思想:如果A模块向B模块传递信息,推荐参数使用基本数据类型,而不是以model形式提供,否则A模块依赖同一个model,B模块也依赖同一个model,这样模块间还是存在相互依赖,没有达到真正完全耦合。


实现原理


  • 基于OC的runtimecategory特性动态获取模块
  • 通过NSClassFromString动态获取类,并创建实例
  • 通过NSSelectorFromString动态获取SEL
  • 通过performSelector+NSInvocation动态调用方法
  • performSelector响应OC的动态性,将方法的绑定延迟到运行时,即在编译阶段不会检测方法的有效性(如果方法不存在也不会报错)。
  • 如果方法名未知可能会引起内存泄漏相关问题,可以通过以下代码忽略此警告
//如果方法名称是动态不确定的,会有如下提示
⚠️ PerformSelector may cause a leak because its selector is unknown
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self performSelector:selector];
#pragma clang diagnostic pop
  • performSelector提供动态执行方法的能力
  • NSInvocation提供了消息调用的能力
  • 方法调用的本质是消息发送,即底层调用的是objc_msgSend,可以从objc源码得到验证

- (id)performSelector:(SEL)sel withObject:(id)obj {
  if (!sel) [self doesNotRecognizeSelector:sel];
  return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);
}


源码分析


通过阅读CTMediator的源码可知,以下是源码的通讯过程图示

image.png

以上是组件化方案的一个简化版架构描述,主要是基于Mediator模式Target-Action模式,中间采用了runtime来完成调用。这套组件化方案将远程应用调用和本地应用调用做了拆分,而且是由本地应用调用为远程应用调用提供服务


CTMediator调用的方式有两种(伪代码实现)


  • 本地组件化通讯:本地原生模块间的调用
- (id _Nullable )performTarget:action:params:shouldCacheTarget:{
    //拼接类名字符串
    NSString *targetClassString = "Target_" + targetNaem;
    //从缓存中获取类
    NSObject *target = [self safeFetchCachedTarget:targetClassString]
    if (缓存中没有target){
        Class targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }
    //拼接方法字符串
    NSString *actionString = "Action_" + actionName;
    //生成SEL
    SEL action = NSSelectorFromString(actionString);
    if (target为空){
        处理target为空的情况
    }
    //是否缓存target
    if (shouldCacheTarget) {
        //以key-value的形式缓存
        (key:target, value:targetClassString)
    }
    //判断target是否响应action
    if ([target respondsToSelector:action]) {
        return [self safePerformAction:action target:target params:params];
    }else{
        处理target未响应action的情况
    }
}
- (id)safePerformAction:target:params:{
    //根据action生成签名
    NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
    //根据不同的返回类型,进行封装
    //根据签名对象创建调用对象invocation
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
    invocation设置target、action、params
    //消息调用
    [invocation invoke];
    //提供动态执行方法
    return [target performSelector:action withObject:params];
}
  • 远程组件化通讯:其他app调用,主要是通过openURL的方式,需要在AppDelegate的openUrl代理方法中进行处理
- (id _Nullable)performActionWithUrl:completion:{
    处理url参数 - 遍历并存放到字典中
    处理targetName,目的是为了防止黑客通过远程方式调用本地模块
    [self performTarget:action:params:shouldCacheTarget:];
    回调处理
}


CTMediator使用


传统的界面跳转方式如下,模块间高度耦合


image.png

以下是以Home、Detail模块为例,通过CTMediator的解耦方式

image.png

以下是Demo代码的整体结构

image.png

整体结构


具体的实现代码如下


  • Home模块实现的核心代码如下

- (void)pushDetailAction:(UIButton *)sender{
  UIViewController *vc = [MIM() MIMediator_pushDetail];
  [self.navigationController pushViewController:vc animated:YES];
}
  • Detail模块实现的核心代码如下

- (void)showAlert{
//  [[MIMediator sharedInstance] MIMediator_showAlert];
  [MIM() MIMediator_showAlert]; 
}

可以简化组件化单例调用方式

// 简化调用单例的函数
MIMediator* _Nonnull MIMD(void);
  • 组件化通讯实现的代码如下
//MIMediator+Universal中的实现
- (UIViewController *)MIMediator_pushDetail{
  UIViewController *vc = [self performTarget:kMIMediatorTargetDetail action:kMIMediatorActionPushDetail params:nil shouldCacheTarget:NO];
  if ([vc isKindOfClass:[UIViewController class]]) {
    return vc;
  }else{
    return [[UIViewController alloc] init];;
  }
}
- (void)MIMediator_showAlert{
  [self performTarget:kMIMediatorTargetDetail action:kMIMediatorActionShowAlert params:nil shouldCacheTarget:NO];
}
//Target_Detail中的实现
- (UIViewController *)Action_pushToDetail:(NSDictionary *)param{
  DetailViewController *detailVC = [[DetailViewController alloc] init];
  detailVC.title = @"详情页";
  return detailVC;
}
- (id)Action_showAlert:(NSDictionary *)dic{
  UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"alert title" message:@"alert message" preferredStyle:UIAlertControllerStyleAlert];
  [alertVC addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:nil]];
  [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertVC animated:YES completion:nil];
  return nil;
}

参考链接:

相关文章
|
开发者 iOS开发
iOS 源码分析(三):MLeaksFinder
iOS 源码分析(三):MLeaksFinder
736 0
iOS 源码分析(三):MLeaksFinder
|
JSON 数据格式 iOS开发
iOS 源码分析(二):YYModel
iOS 源码分析(二):YYModel
597 0
iOS 源码分析(二):YYModel
|
缓存 算法 安全
iOS-底层原理 06:malloc 源码分析 思路
iOS-底层原理 06:malloc 源码分析 思路
422 0
iOS-底层原理 06:malloc 源码分析 思路
|
iOS开发
iOS-底层原理 04:NSObject的alloc 源码分析
iOS-底层原理 04:NSObject的alloc 源码分析
132 0
iOS-底层原理 04:NSObject的alloc 源码分析
|
存储 算法 安全
iOS-底层原理 02:alloc & init & new 源码分析
iOS-底层原理 02:alloc & init & new 源码分析
142 0
iOS-底层原理 02:alloc & init & new 源码分析
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
112 1
|
10天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
31 9
|
9天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
7天前
|
iOS开发 开发者
探索iOS开发中的SwiftUI框架
【10月更文挑战第39天】在苹果的生态系统中,SwiftUI框架以其声明式语法和易用性成为开发者的新宠。本文将深入SwiftUI的核心概念,通过实际案例展示如何利用这一框架快速构建用户界面,并探讨其对iOS应用开发流程的影响。