组件化Pods管理 | 命令模式 | target-action | 路由传参 | Router

准备工作

// 返回值id
// 外部调用, 通过target和action来唯一确认一个类里面的方法
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName param:(NSDictionary *)para;
  • 说明

  1. target-action 两个参数来确定target 和 action , para 你需要传递的参数

接口实现

- (id)performTarget:(NSString *)targetName action:(NSString *)actionName param:(NSDictionary *)para {
    
    // 这个目标的类名字符串
    NSString *targetClassString = [NSString stringWithFormat:@"RYLSJTA_%@",targetName];
    NSString *actionMethondString = [NSString stringWithFormat:@"action_%@:",actionName];
    
    Class targetClass = NSClassFromString(targetClassString);
    NSObject *target = [[targetClass alloc] init];
    
    SEL action = NSSelectorFromString(actionMethondString);
    // 判断
    if ([target respondsToSelector:action]) {
        return [self safePerformAction:action target:target param:para];
        
    } else {
        
        SEL action = NSSelectorFromString(@"notFound:");
        if ([target respondsToSelector:action]) {
            return [self safePerformAction:action target:target param:para];
            
        } else {
            return nil;
        }
    }
    return nil;
}
  • 说明

  1. 返回值使用ID类型是因为我们可能在模块中得到的是一个登录的控制器,而不是其它类型。
  2. 如果没有需要的类或者实现的方法我们需要做额外的处理,防止崩溃
  3. 如果你有参数传递需要处理的话 需要在 action_%@: 这里加上个冒号不然没有反应

传递的参数处理(核心代码)

// 1.通过对象调用指定的方法
// 2.传参
- (id)safePerformAction:(SEL)action target:(NSObject *)target param:(NSDictionary *)para {
    NSMethodSignature *methodSig = [target methodSignatureForSelector:action];
    if (methodSig == nil) {
        return nil;
    }
    
    // 方法签名的返回值
    const char *retType = [methodSig methodReturnType];
    
    // id 是可以返回任意对象 所以 我们单独处理基本变量. NSInteger Bool Void...
    if (strcmp(retType, @encode(NSInteger)) == 0) {
        //通过方法调用者创建方法签名;此方法是NSObject 的方法
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        // 为什么传2? 前面0和1这两个位置已经被target和action给占用了.
        [invocation setArgument:¶ atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        // 执行invocation
        [invocation invoke];
        
        NSInteger result = 0;
        [invocation getReturnValue:&result];
            return @(result);
    }
    
    if (strcmp(retType, @encode(BOOL)) == 0) {
        // 通过方法调用者创建方法签名;此方法是NSObject 的方法
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        
        // 为什么传2? 前面0和1这两个位置已经被target和action给占用了.
        [invocation setArgument:¶ atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        // 执行invocation
        [invocation invoke];
        
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    return [target performSelector:action withObject:target withObject:para];
    #pragma clang diagnostic pop
}
  • 说明

  1. setArgument 设置参数一定要从2开始,因为里面模式是self和_cmd 2个给占用了
  2. 如果有多个参数的话 就atIndex:3,atIndex:4 这种形式就可以
  3. strcmp(retType, @encode(BOOL) 转码判断,这里的类型可以根据情况设置
  4. 使用push pop 是为了消除警告,因为我们在上面已经处理过了,我们已经知道了类型,所以这里消除警告即可
  • 实现效果

最终开发想要的效果
  • 测试效果

Router Demo 测试结果展示
  • Demo分享

RYLSJRouter下载链接

你可能感兴趣的:(组件化Pods管理 | 命令模式 | target-action | 路由传参 | Router)