CTMediator理解

2021-07-06  本文已影响0人  哥只是个菜鸟

1.CTMediator作为路由中间件跳转,很大程度解决了各种文件依赖,更加灵活,比较适用于电商活动等需要各种跳转页面的项目

2.我们需要在外面定义好路由的url和安卓端统一,比如:xxx://shop/detail?id=1234

3.新建一个类,名字按照路由的格式定义,比如:Target_shop,shop表示你要跳转的页面,我这边是购物车页面,里面的函数命名也按照路由定义,比如Action_detail,这个页面暂时没有入参,最终根据传入的url调用这里的方法拿到控制器进行跳转

UIViewController *vc = [[CTMediator sharedInstance] performActionWithUrl:url completion:nil];
[self.navigationController pushViewController:vc animated:YES];
@interface Target_shop : NSObject

- (UIViewController *)Action_detail:(NSDictionary *)params;

@end
@implementation Target_shop

- (UIViewController *)Action_detail:(NSDictionary *)params {
    ShopCarViewController *vc = [[ShopCarViewController alloc] init];
    vc.hidesBottomBarWhenPushed = YES;
    return vc;
}

@end

4.源码实现

 NSString *swiftModuleName = params[kCTMediatorParamsKeySwiftTargetModuleName];
    
    // generate target
    NSString *targetClassString = nil;
    if (swiftModuleName.length > 0) {
        targetClassString = [NSString stringWithFormat:@"%@.Target_%@", swiftModuleName, targetName];
    } else {
        targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
    }
    NSObject *target = [self safeFetchCachedTarget:targetClassString];
    if (target == nil) {
        Class targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }

    // generate action
    NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
    SEL action = NSSelectorFromString(actionString);
// 1.通过target和action生成方法前方法签名
NSMethodSignature* methodSig = [target methodSignatureForSelector:action];

// 2.通过方法签名生成NSInvaocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];

// 3.设置参数位置在第3个位置,有默认值两个参数 self _cmd
[invocation setArgument:&params atIndex:2];

// 4.设置action
[invocation setSelector:action];

// 5.设置target
[invocation setTarget:target];

// 6.开始调用
[invocation invoke];


 id result;
// 7.获得方法的返回值
[invocation getReturnValue:&result];

消息转发流程

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(requestOne1)) {
        IMP sayOIMP = class_getMethodImplementation(self, @selector(requestOne));
        Method sayOMethod = class_getClassMethod(self, @selector(requestOne));
        const char *sayOType = method_getTypeEncoding(sayOMethod);
        return class_addMethod(self, sel, sayOIMP, sayOType);
    }
    return [super resolveClassMethod:sel];
}
- (void)requestOne {
    
}

- (id)forwardingTargetForSelector:(SEL)aSelector {//快速转发
    if ([NSStringFromSelector(aSelector) isEqualToString:@"requestOne"]) {
        return [ViewController2 alloc];
    }
    return [super forwardingTargetForSelector:aSelector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSLog(@"%s -- %@",__func__,NSStringFromSelector(aSelector));
    if (aSelector == @selector(requestOne)) { // v @ :
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

//
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    NSLog(@"%s ",__func__);
    SEL aSelector = [anInvocation selector];

    if ([[ViewController2 alloc] respondsToSelector:aSelector]) {
        [anInvocation invokeWithTarget:[ViewController2 alloc]];
    } else {
        [super forwardInvocation:anInvocation];
    }
}
- (NSMethodSignature *)hook_methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature* signature = [self hook_methodSignatureForSelector:aSelector];
    if (signature) {
        return signature;
    }
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

- (void)hook_forwardInvocation:(NSInvocation *)anInvocation {
    NSString *message = [NSString
        stringWithFormat:@"Unrecognized instance class:%@ and selector:%@", NSStringFromClass(self.class), NSStringFromSelector(anInvocation.selector)];
    NSLog(@"%@",message);
}

runtime实现模型和字典互转

((id (*)(id _Nullable, SEL _Nonnull,
                     id))(void *)objc_msgSend)(self, selector, value);
#import "DemoModel.h"
#import <objc/message.h>
#import <objc/runtime.h>

@implementation DemoModel

- (instancetype)dictionaryToModel:(NSDictionary *)dictionary {
    NSArray *keyArr = [dictionary allKeys];
    for (int i = 0; i < keyArr.count; i++) {
        NSString *key = keyArr[I];
        id value = [dictionary valueForKey:key];
        //key首字母大写
        NSString *setName = [NSString stringWithFormat:@"set%@:",key.capitalizedString];
        //生成set方法
        SEL selector = NSSelectorFromString(setName);
        if ([self respondsToSelector:selector]) {
            ((id (*)(id _Nullable, SEL _Nonnull,
                     id))(void *)objc_msgSend)(self, selector, value);
            //objc_msgSend函数是无返回参数的函数,需要把它强制转化类型
        } else {
            NSLog(@"生成%@set方法失败", key.capitalizedString);
        }
    }
    return self;
}

- (NSDictionary *)modelToDictionary {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    unsigned int count = 0;
    objc_property_t *propertys = class_copyPropertyList(self.class, &count);
    for (int i = 0; i < count; i++) {
        objc_property_t property = propertys[I];
        const char *name = property_getName(property);
        NSString *properyName = [NSString stringWithUTF8String:name];
        //生成get方法
        SEL selector = NSSelectorFromString(properyName);
        if ([self respondsToSelector:selector]) {
            id value = ((id (*)(id _Nullable, SEL _Nonnull))(void *)objc_msgSend)(self, selector);
            [dict setValue:value forKey:properyName];
        } else {
            NSLog(@"没找到该属性%@",properyName);
        }
    }
    free(propertys);
    return dict;
}


@end
上一篇下一篇

猜你喜欢

热点阅读