美文网首页
runtime(四)-常见操作

runtime(四)-常见操作

作者: George_Luofz | 来源:发表于2018-04-07 12:37 被阅读4次

    runtime很复杂庞大,懂了oc对象布局,理解了发消息过程和消息转发流程,还不够。
    接下来再学习一些常见用法,因为我们学到的那些毕竟是系统如何用的,自己会用才行。
    runtime可以创建一个类,对一个类做各种改造:添加属性/变量、添加方法、添加协议

    1. 方法替换/新增方法
      替换两个方法的imp,一般将替换操作放在load方法中(load方法在类加载时就会触发,这样在程序运行时就已经替换完毕了,相当于一个速度的优化;而且该方法只会执行一次,不会出现重复替换的情况)
    + (void)load{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            SEL originalSEL = @selector(say);
            SEL newSEL = @selector(newSay);
            Method originalMethod = class_getInstanceMethod(self, originalSEL);
            Method newMethod = class_getInstanceMethod(self, newSEL);
            // 添加一个方法
            BOOL flag = class_addMethod(self, originalSEL, method_getImplementation(newMethod), "v@:");
            if(flag){
                // 替换一个SEL的实现
                class_replaceMethod(self, newSEL, method_getImplementation(originalMethod), "v@:");
            }else{
                // 交换两个方法的实现
                method_exchangeImplementations(originalMethod, newMethod);
            }
        });
    }
    
    1. 消息转发
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if([NSStringFromSelector(sel) isEqualToString:@"test"]){
            Method method = class_getInstanceMethod(self, @selector(_testIMP));
            bool success = class_addMethod(self, @selector(test), method_getImplementation(method), "v@:");
            if(success) return YES;
            return NO;
        }
        return NO;
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        if([NSStringFromSelector(aSelector) isEqualToString:@"test"]){
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
        
        return [super methodSignatureForSelector:aSelector];
    }
    -(id)forwardingTargetForSelector:(SEL)aSelector{
    //    if([NSStringFromSelector(aSelector) isEqualToString:@"test"]){
    //        return [[TestObj alloc] init];
    //    }
        return [super forwardingTargetForSelector:aSelector];
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
    //    SEL sel = anInvocation.selector;
    //    if([NSStringFromSelector(sel) isEqualToString:@"test"]){
    //        TestObj *obj = [TestObj new];
    //        if([obj respondsToSelector:sel]){
    //            [anInvocation invokeWithTarget:obj];
    //            return;
    //        }
    //    }
        [super forwardInvocation:anInvocation];
    }
    

    可以在三个位置处理消息转发,在runtime(二)有说明

    1. category加属性
    static char * keyName = "KAPropKey";
    
    - (void)setProp:(NSString *)prop{
        objc_setAssociatedObject(self, keyName, prop, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)prop{
       return objc_getAssociatedObject(self, keyName);
    }
    

    OBJC_ASSOCIATION_COPY_NONATOMIC有几种取值,参照doc:

    typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
        OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
        OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                                *   The association is not made atomically. */
        OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                                *   The association is not made atomically. */
        OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                                *   The association is made atomically. */
        OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                                *   The association is made atomically. */
    };
    

    _NONATOMIC加下划线的表示非原子性,相当于@property(nonatomic)
    关于category加属性如何实现,在category专题学习

    1. json转model
      其实思路就是利用runtime获取property列表,然后取出json中的键值对,使用KVC为每一个property赋值
      举个栗子:
    - (void)_test_jsonToModel{
        NSDictionary *dict = @{@"prop":@"value",@"prop2":@"value2",@"prop3":@"value3"};
        
        TestRuntimeForward *model = [TestRuntimeForward new];
    
        unsigned int count = 0;
       // 获取属性列表
        objc_property_t *propList =  class_copyPropertyList(objc_getClass("TestRuntimeForward"), &count);
        for(int i = 0 ; i < count;i++){
            objc_property_t prop = propList[i];
            const char *name = property_getName(prop);
            NSString *nameStr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            // 取值
            id value = [dict valueForKey:nameStr];
            if(value){
                // KVC设值
                [model setValue:value forKey:nameStr];
            }
        }
        free(propList);
        NSLog(@"model:%@",model);
    }
    输出结果
    2018-04-07 12:36:28.983197+0800 iOSLearnigDemo[13232:1087932] model:prop=value
    

    持续整理中

    相关文章

      网友评论

          本文标题:runtime(四)-常见操作

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