美文网首页 iOS进阶之路由iOS项目组件化iOS组件化架构
组件化Pods管理 | 命令模式 | target-action

组件化Pods管理 | 命令模式 | target-action

作者: 字符管理师 | 来源:发表于2019-07-25 16:37 被阅读4次

    准备工作

    // 返回值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:&para 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:&para 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

        本文链接:https://www.haomeiwen.com/subject/aonhrctx.html