CTMediator 学习使用总结

先来看看 NSMethodSignature 和 NSInvocation

假设现在有一个方法

 -(NSString *)school:(NSString *)name time:(NSInteger)t{
    NSString *result = [NSString stringWithFormat:@"%@%d",name,t];
    NSLog(@"---result-----%@", result);
    return result;
} 

常规掉用我们都知道 现在我们使用 NSMethodSignature 和 NSInvocation 怎么玩
NSMethodSignature *signature = [self methodSignatureForSelector:@selector(schoolNmae:time:)];
NSMethodSignature 获得方法签名 有两种方式

  1. methodSignatureForSelector 通过类掉用则是获得类方法 的 签名 通过 类对象掉用 则是获得实例方法的签名
  2. instanceMethodSignatureForSelector 只能获得实例方法的签名 并且只能用类去掉用

NSMethodSignature 有几个属性 分别为

  1. methodReturnType 返回值类型 v(无返回值) @(对象) i(int) f(float)
  2. methodReturnLength 大于0 代表有返回值
  3. numberOfArguments 参数个数 这里 schoolNmae 方法是4个参数 为什么? 我们使用 clang -rewrite-objc 文件名 将方法转成C语言源代码 可以发现 方法变成了 下面这样
static NSString * _I_MyTest_school_time_(MyTest * self, SEL _cmd, NSString *name, NSInteger t) {
    NSString *result = ((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_5l_l354rhkd3sl86kc7m8d8nwrr0000gn_T_MyTest_92ee17_mi_2, (NSString *)name, (NSInteger)t);
    return result;
} 

可以看到 多了 MyTest * self, SEL _cmd这两个 参数 加上原本的 共4个
*** NSInvocation 使用 ***

设置方法
 [invocation setSelector:@selector(school:time:)];
 设置参数 在第二个位置 
 [invocation setArgument:&name atIndex:2];
 设置参数 在第三个位置
 [invocation setArgument:&t atIndex:3];
 设置掉用对象
 [invocation setTarget:self];
 参数引用计数 加1 
 [invocation retainArguments];
 掉用方法
 [invocation invoke];
 NSString *result = @"";
 获取最后的返回值
 [invocation getReturnValue:&result];

注意上面获取返回值是有问题的 程序直接崩溃 为什么 ?
因为在arc 模式下 NSString *result = @""; 这样的声名 result 是__strong 的 但是 getReturnValue 只是把值拷贝到指定的内存地址 引用计数并没有加一 也就是说result没有获得返回值的强引用 当返回值出了作用域 会被释放 同时因为我们的 result 是__strong的 所以arc会误认为我们是强引用过了 所以 result 的声名 改成 __unsafe_unretained NSString *result = @""; 就好了 arc会给我们处理

再来看看CTMediator

  1. 使用方法
    [[CTMediator sharedInstance] performTarget:@"A" action:@"GetName" params:@{@"key":@"value"} shouldCacheTarget:YES];
    performTarget
    target 是我们要掉用的类 action是我们要掉用的方法 params 是我们要传入的参数 CTMediator 的 performTarget 方法 比较长这里只列出几行代码
拿到我们要掉用的类 注意只能 以 Target_ 开头的 
targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
从缓存中拿到我们的目标类对象 如果没有就创建一个
NSObject *target = self.cachedTarget[targetClassString];
   if (target == nil) {
       Class targetClass = NSClassFromString(targetClassString);
       target = [[targetClass alloc] init];
   }
   拿到目标方法 注意只接受 Action_ 开头的方法
   NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
   SEL action = NSSelectorFromString(actionString);
   if (shouldCacheTarget) {
       self.cachedTarget[targetClassString] = target;
   }
   如果方法相应 执行
   if ([target respondsToSelector:action]) {
       return [self safePerformAction:action target:target params:params];
   }

safePerformAction
仍然我们只粘贴其中一段代码

	NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
	if(methodSig == nil) {
        return nil;
    }
    const char* retType = [methodSig methodReturnType];
    if (strcmp(retType, @encode(void)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        return nil;
    }

这里就用到了我们最开始讲的内容不再赘述 至此一个方法掉用完毕 当然还有一些异常处理 这里不再将 看源代码 一看就懂

总结

今天写这个用什么用呢 其实我在工作中没有直接用这种方法调用过方法,前几天看了一种设计模式 中介者模式 这种模式我个人觉得是用来协调组件之间掉用逻辑的模式 组件内部我们可以使用MVVM MVC 等。在掉用组件的时候 为这个组件创建一个CTMediator的类别 所有跟这个组件之间的交互 都只依赖这个中介者 实现了组件间的解偶合

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值