Runtime

作者: 音吹 | 来源:发表于2016-07-21 00:09 被阅读42次

    Runtime消息机制

    • 1.导入<objc/message.h>
    • 2.Build Setting --> msg --> 设为NO
      目前底层实现是是用 对象 performSelector(方法名);
      使用objc_msgSend(对象或者类对象,方法,参数);

    相关头文件:objc/runtime.h

    • 3.objc_allocateClassPair:创建新的类;
    • 4.class_addMethod:给类增加新的方法;
    • 5.object_getClass:获得对象的isa指针所指向的对象;
    • 6.objc_registerClassPair:注册新的类;
    - (void)viewDidLoad {
        [super viewDidLoad];
        //创建了一个LvCustomView类  属于View的子类
        Class newClass = objc_allocateClassPair([UIView class], "LvCustomView", 0);
        //该类增加一个report的方法
        class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
        //注册该类
        objc_registerClassPair(newClass);
    }
    
    
    void ReportFunction(id self,SEL _cmd)
    {
        NSLog(@"This obj is %p",self);
        
    }
    

    Method Swizzling

    • 7.class_replaceMethod:替换类方法的定义;
    • 8.method_exchangeImplementations:交换两个方法;
    • 9.method_setImplementation:设置一个方法的实现;
      1. Method imageNamed = class_getClassMethod([UIImage class], @selector(imageNamed:));:获得类方法;
      1. class_getInstanceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>):获得对象方法;

    动态调用方法

    当对象调用performSelector:@selector(方法名)的时候,系统会去对象的类中查看是否存在该方法;
    在类中重写父类方法

    void eat(id self,SEL _cmd)
    {
    
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        if (sel == @selector(eat)) {
            
            //第一个参数:给哪个类添加方法
            //二:SEL,添加方法的方法编号是什么
            //三:IMP,方法实现,函数入口,函数名字
            //四:types:方法类型
            //v:void   @:表示对象 :SEL,是方法编号
            class_addMethod(self, sel, (IMP)eat, "v@:");
            
            return YES;
            
        }
        
        return [super resolveInstanceMethod:sel];
    }
    

    动态添加分类的属性

    一般是给分类添加属性关联

    @property (nonatomic,strong) NSString *name;
    
    - (void)setName:(NSString *)name
    {
        //第一个:给哪个对象添加属性;
        //二:key:属性名,根据key去获取关联的对象, void * == id;
        //三:value:关联的值;
        //四:存储策略
        
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
    }
    - (NSString *)name
    {
        return objc_getAssociatedObject(self, @"name");
    }
    

    Runtime实现KVC

    • 我们现在创建Model的时候一般使用下面方法进行赋值
        DataModel * dataModel = [DataModel dataWithDict:dict];
    
    

    在Model类中实现:

    + (DataModel *)dataWithDict:(NSDictionary *)dict
    {
        DataModel * dataModel = [[self alloc] init];
        [dataModel setValuesForKeysWithDictionary:dict];
        return dataModel;
    }
    

    这样是不用三方库情况下通常的赋值方式

    • 同样可以通过runtime进行这样的操作;
      创建NSObject分类 在分类中实现传入字典 返回已经赋值好的Model对象;
      基本原理就是:遍历模型中所有成员属性,去字典中查找对应的Value进行赋值;
      类里面有一个属性列表(数组)
    + (instancetype)modelWithDict:(NSDictionary *)dict{
        
        //创建对应类的对象
        id objc = [[self alloc] init];
        
        // 遍历模型所有成员属性
        // ivar:成员属性
        // class_copyIvarList:把成员属性列表复制一份给你
        // Ivar *:指向一个成员变量数组
        // class:获取哪个类的成员属性列表
        // count:成员属性总数
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList(self, &count);
        //&count这里会自动把self的成员属性个数返回给count
        for (int i = 0 ; i < count; i++) {
            // 获取成员属性
            Ivar ivar = ivarList[i];
            // 获取成员名
           NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
            ;
            // 获取key 因为成员属性前面加了_ 符号, 所以要去除
            NSString *key = [propertyName substringFromIndex:1];
            // 获取字典的value
            id value = dict[key];
            // 给模型的属性赋值
            // value:字典的值
            // key:属性名
            
            // 成员属性类型
            NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
            // 二级转换
            // 如果将是NSDictionary的Value也写成一个模型,那么就需要进行二级转换
            if ([value isKindOfClass:[NSDictionary class]] && ![propertyType isEqualToString:@"@\"NSDictionary\""]) {
    
                // @"@\"二级模型名\""
                NSRange range = [propertyType rangeOfString:@"\""];
                propertyType = [propertyType substringFromIndex:range.location + range.length];
                range = [propertyType rangeOfString:@"\""];
                propertyType = [propertyType substringToIndex:range.location];
                
                // 获取需要转换类的类对象
               Class modelClass =  NSClassFromString(propertyType);
            
                if (modelClass) {
                    //将二级模型进行赋值操作
                    value =  [modelClass modelWithDict:value];
                    
                }
            }
            if (value) {
                //KVC赋值不能为空
                [objc setValue:value forKey:key];
                
            }
    
        }
        return objc;
    }
    

    注:Ivar: 这个跟char用法差不多
    Ivar * :指向数组;
    Ivar ivar: 创建一个对象;
    Ivar * 跟 Ivar arr[] 意思一样;
    还在学习中,Ivar只是个人理解,可能会有不对或者有出入的地方,欢迎指正,谢谢!

    相关文章

      网友评论

          本文标题:Runtime

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