Runtime

作者: Zorin | 来源:发表于2020-05-26 18:24 被阅读0次

    定义

    runtime 详解文章


    1. 消息转发

    1. 动态方法解析(方法调用的必经之路)
    + (BOOL)resolveClassMethod:(SEL)sel {
        // 获取方法名称
        NSString * selName = [NSString stringWithFormat:@"%@",NSStringFromSelector(sel)];
        // 当识别到 某个方法时 可以动态的添加进来
        if ([selName isEqualToString:@"testMethod"]) {
            //为该类动态添加一个方法testFunction处理消息,并执行该方法
            class_addMethod([self class], sel, (IMP)testFunction, "v@:");
            return true;
     }
        return false;
    
    }
    + (BOOL)resolveInstanceMethod:(SEL)sel {
    
    }
    
    1. 快速转发(动态解析失败后,指定一个接收方法的对象)
    /// 快速转发
    - (id) forwoardingTargetForSelector:(SEL)aSelector {
       NSString * methodName = NSStringFromSelector(aSelector);
      if ([methodName isEqualToString:@"sendMessage:"])
      {
         return [CustomClass new];
      }
      return  [super forwordingTargetForSelector:aSelector];
    }
    
    1. 完整的消息转发(1. 消息签名 2. 转发请求)
    #pragma mark 慢速转发
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        NSString * methodName = NSStringFromSelector(aSelector);
        if ([methodName isEqualToString:@"sendMessage:"]) {
            return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
        }
        return [super methodSignatureForSelector:aSelector];
    };
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        SEL sel = [anInvocation selector];
        CustomClass * obj = [CustomClass new];
        if ([obj respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:obj];
        } else {
            [super forwardInvocation:anInvocation];
        }  
    }
    
    
    1. 未识别到方法
    - (void)doesNotRecognizeSelector:(SEL)aSelector {
          ///   未识别到方法的调用
    }
    

    2. Method Swizzling(方法转换)

    + (void)load {
        ///  对 原方法  和 新方法 进行调换
        Method originMethod  = class_getInstanceMethod(self,@selector(reloadData));
        Method currentMethod = class_getInstanceMethod(self,@selector(lg_reloadData));
        method_exchangeImplementations(originMethod,currentMethod);
    
    }
    /*
    当调用 reload 的时候 就会自动调用 这个方法了
    */
    - (void)lg_reloadData {
        [self lg_reloadData];
        [self fillDefaultView];
    }
    /*
    当数据源没有数据的话,添加默认数据
    */
    - (void)fillDefaultView {
        
    }
    

    3. 字典和模型的相互转换

    /// 字典转模型
    //1.  遍历字典的allKeys 
    //2.  在for循环中,动态调用model 的 (key值前拼接set) 方法名,对model 的属性进行set赋值
    - (instancetype)initWithDic:(NSDictionary *)dic {
        self = [super init];
        if (self) {
             for (NSString * key in dic.allKeys) {
                   id value = dic[key];
                   NSString * methodName = [NSString stringWithFormat:@"set%@:",key.capitalizedString];
                   SEL sel = NSSelectorFromString(methodName);             
                   if (sel) {
                         ((void(*)(id,SEL,id)) objc_msgSend) (self, sel, value);
                   }
    
             }  
     
        }
    
    }
    
    
    /// 模型转字典
    //1.  遍历模型的属性名称( class_getPropertyList(),获取属性列表 )
    //2.  遍历过程中获取,属性value 值,赋值给字典
    - (NSDictionary *)convertModelToDic {
        unsigned int count = 0;
        objc_property_t * properties = class_copyPropertyList(self,&count);
        if (count != 0) {
             NSMutalbeDictionary * tempDic = [@{ } mutableCopy];
             for (int i = 0; i < count; i ++ ) {
                   //  属性名称
                   const void * propertyName = property_getName(propertied[i]);
                  // 根据属性名称 得到获取属性value 的get方法
                   SEL sel = NSSelectorFromString(name);
                   if (sel) { 
                         id value = ((id(*)(id, SEL, id )) objc_msgSend) (self, sel);
                        if (value) {
                                tempDic[name] = value;
                        } else {
                                temDic[name] = @"";
                        }      
                   }
             }
             free(properties); //被copy到了堆区   要释放空间
             return tempDic;
        }
        free(properties);
        return  tempDic;
    }
    

    4. 自定义KVO

    1. 当一个对象的方法被监听时,会自动生成一个该对象父类的子类,
    2. 并且该对象指向这个新类,也就是多了一个中间类,这个中间类的作用就是重写,被监听属性的set方法,并发送被修改的通知
    - (vod)lg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
          //1. 创建中间类
         Class customClass =  objc_allocateClassPair([self class],newName.UTF8String, 0);
         objc_registerClassPair(customClass);
    
         //  2. 修改self的isa指针,指向 中间类
         object_setClass(self, customClass);
    
         // 3. 重写 中间类的setter 方法 被通知 被通知者 值被改变
         NSString * methodName = [NSString stringWithFormat:@"set%@:",keyPath.capitalizedString];
         SEL sel = NSSelectorFromString(methodName);
         class_addMethod(customClass, sel, (IMP)setterMethod, "v@:@");
         objc_setAssociatedObject(self, (__bridge const void *)@"objc",observer,  OBJC_ASSOCIATION_ASSIGN);
    
    }
    void setterMethod(id self,SEL _cmd,NSString *name) {
          // 1、调用父类方法
          // 2、通知观察者
         struct objc_super superClass = {
                self,
                class_getSuperclass([self class])
         };
         //  调用父类的修改方法
         objc_msgSendSuper(&superClass, _cmd ,name);
        // 观察者
         id observer = objc_getAssociatedObject(self, (__bridge const  void *)@"objc");
        // 告诉观察者 数值被修改
       NSString * methodName = NSStringFromSelector(_cmd);
       NSString * key = @""; // keyPath 方法名 去除set 后 首字母小写
       objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),key,self,@{key:name},nil);
    }
    
    
    
    
    
    

    // 引用类型 和 值类型 ??/

    相关文章

      网友评论

          本文标题:Runtime

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