什么是runtime?

runtime是一套纯c的API.平时用oc写的代码在运行时都会先转成runtime代码,然后在执行。

runtime可以干什么?

1.交换方法。(method_exchangeImplementations)

  首先创建一个People类,有俩个类方法,+(void)run{NSLog@"跑"}和+(void)sing{NSLog@"唱歌"}.

  依次调用这两个方法,控制台会依次输出 跑 和 唱歌 。

  用runtime获取到People类的run方法。

  Method m1=class_getClassMethod([People class], @selector(run)) ;

  同理获取sing方法。

  Method m2=class_getClassMethod([People class], @selector(sing)) ;

  交换两个方法。

  method_exchangeImplementations(m1, m2) ;

  在依次调用这个两个方法,控制台会输出 唱歌 和 跑。

  实例方法用 class_getInstanceMethod 来获取。

 

2.在分类中设置属性。

  众所周知,在分类中是无法添加实例变量的。就算在分类中声明了一个属性,也只是生成了这个属性的set方法和get方法,并不会生成这个属性。并且,虽然打点调用会有

  提示,但是一旦运行程序就会崩溃。所以要想在分类中添加实例变量还得使用runtime来操作。

  使用到的是  

  void objc_setAssociatedObject(id object , const void *key ,id value ,objc_AssociationPolicy policy) 这个方法。

  其中:

  object就是你想要添加属性的对象。

  key则是你想保存的属性的键。

  value则是你想保存的属性的值。

  policy则是你想保存的属性的属性(assign,copy之类的)。

  比如在一个分类中声明了一个属性。

  @property(nonatomic,copy)NSString* name

  在其set方法中这么调用:

  char nameKey ;//声明属性的键。

  -(void)setName:(NSString *)name

  {

    objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC) ;//关联 键和值

  }

  在其get方法中这么调用来获取这个属性:

  -(NSString* )name

  {

    return objc_getAssociatedObject(self, &nameKey) ;

  }

  这样就在分类中添加了一个属性。

 

3.获取一个类的所有属性。

  -(void)getPropertyFromPeople

  {

    unsigned int outcount ;

    Ivar* ivars=class_copyIvarList([People class],&outcount) ;//会返回属性的个数,outcount即为总个数

    for(int i=0;i<outcount;i++)

    {

       Ivar ivar=ivars[i] ;

       const char* name=ivar_getName(ivar) ;

       const char* type=ivar_getTypeEncoding(ivar) ;

       NSLog(@"属性名称%s 类型%s",name,type) ;

     }

    free(ivars) ;//注意释放内存

  } 

 

4.将dict转换成model类。

  将方法写在NSObject的分类中,然后model类继承于NSObject,在导入分类的头文件。

-(instancetype)modelWithDictionary:(NSDictionary* )dict

{

    

    Class modelClass=self.class ;

    while (modelClass&&modelClass!=[NSObject class]) {

        unsigned int count=0 ;

        Ivar* ivars=class_copyIvarList(modelClass, &count) ;

        for (int i=0; i<count; i++) {

            Ivar ivar=ivars[i] ;

            NSString* key=[NSString stringWithUTF8String:ivar_getName(ivar)] ;

            key=[key substringFromIndex:1] ;

            id value=dict[key] ;

            if (value==nil) {

                continue ;

            }

            NSString* type=[NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)] ;

            //type的格式为@“@\“NSString\””

            NSRange range=[type rangeOfString:@"@"] ;

            if (range.location!=NSNotFound) {

                if (![type containsString:@"NS"]) {

                    //是自定义的类型

                    Class another=NSClassFromString([type substringWithRange:NSMakeRange(2, type.length-3)]) ;

                    value=[another secondModelWithDictionary:value] ;

                }else if([[type substringWithRange:NSMakeRange(2, type.length-3)] isEqualToString:@"NSArray"])

                {

                    //包含数组

                    

                    //包含model数据的数组

                    NSArray* array=(NSArray* )value ;

                    NSMutableArray* modelArr=[NSMutableArray array] ;

                    

                    //用于接收数组中model的类型

                    id class ;

                    if ([self respondsToSelector:@selector(classStringByArray)]) {

                        class=[self classStringByArray] ;

                        

                        for (int i=0; i<array.count; i++) {

                            //将数组的数据转换成model添加到临时数组中

                            [modelArr addObject:[class secondModelWithDictionary:array[i]]] ;

                        }

                        

                        value=modelArr ;

                    }  

                    

                }

            }

            [self setValue:value forKey:key] ;

        }

        free(ivars) ;

        modelClass=[modelClass superclass] ;

    }

    return self ;

}

 

 

+(instancetype)secondModelWithDictionary:(NSDictionary* )dict

{

    NSObject* object=[[self alloc]init] ;

    [object modelWithDictionary:dict] ;

    return object ;

}