美文网首页iOSiOS学习
iOS-Runtime原理及使用

iOS-Runtime原理及使用

作者: 指头飞血 | 来源:发表于2016-10-24 15:21 被阅读193次

    Runtime原理

    1.Runtime简称运行时.OC就是运行时机制,(就是系统在运行的时候的一些机制)其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数.对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.

    2.它是一个主要使用C和汇编写的库,为C添加了面相对象的能力并创造了Objective-C.这就是说它在类信息(Class information)中被加载,完成所有的方法分发,方法转发,等等.Objective-C runtime 创建了所有需要的结构体,让Objective-C 的面相对象编程变为可能.

    3.是一套比较底层的纯C语言API,属于1个C语言库, 包含了很多底层的C语言API.在我们平时编写的OC代码中,程序运行过程时,其实最终都是转成了runtime的C语言代码,runtime算是OC的幕后工作者.

    4.因为Objc是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时.也就是说只有编译器是不够的,还需要一个运行时系统(runtime system)来执行编译后的代码.这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石.

    5.Mac和iPhone开发者关心的有两个runtime:Modern Runtime(现代的 Runtime)和 Legacy Runtime(过时的Runtime).Modern Runtime:覆盖所有 64 位的 Mac OS X 应用和所有 iPhone OS 的应用.Legacy Runtime:覆盖其他的所有应用(所有32位的 Mac OS X 应用)Method有2种基本类型的方法.Instance Method(实例方法).Class Method(类方法)

    Runtime简单使用

    Person.h
    @interface Person : NSObject
    @property(nonatomic,copy)NSString *name;
    @property(nonatomic,copy)NSString *gender;
    @property(nonatomic,assign)NSInteger age;
    -(void)eat;
    -(void)play;
    @end
    
    Person.m
    #import "Person.h"
    
    @implementation Person
    -(void)eat{
        NSLog(@"%@吃饭",self.name);
    }
    -(void)play{
        NSLog(@"%@玩",self.name);
    }
    @end
    

    先导入头文件

    #import "RuntimeViewController.h"
    #import "Person+Runtime.h"
    #import "Person.h"
    #import <objc/message.h>//包含消息机制
    #import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
    @interface RuntimeViewController ()
    @end
    @implementation RuntimeViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setTitle:@"runTime"];//动态添加属性,修改属性值(类别"Person+Runtime.h")
        [self exchangeAttribute];//
    //    [self performSelector:@selector(likePlay)];
        objc_msgSend(self,@selector(likePlay));// 动态调用方法(在 LLVM 6.0 中增加了一个 OBJC_OLD_DISPATCH_PROTOTYPES,默认配置在 Apple LLVM 6.0 - Preprocessing 中的 Enable Strict Checking of objc_msgSend Calls 中为Yes 改成NO;)
        [self getAttribute];// 利用runtime遍历一个类的全部成员变量
        [self controlVariables];// 动态控制变量
        [self addMethod];//动态添加方法
        [self exchangeMethod];//动态交换方法实现
    }
    

    1.动态为Category扩展加属性

    Person+Runtime.h
    #import "Person.h"
    
    @interface Person (Runtime)
    @property(nonatomic,copy)NSString *height;// 身高
    -(void)setHeight:(NSString *)height;
    -(NSString *)height;
    -(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2;
    @end
    
    Person+Runtime.m
    #import "Person+Runtime.h"
    #import <objc/message.h>//包含消息机制
    #import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
    @implementation Person (Runtime)
    static char * heightKey = "heightKey";
    -(void)setHeight:(NSString *)height{
         objc_setAssociatedObject(self, heightKey, height, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    -(NSString *)height{
         return objc_getAssociatedObject(self, heightKey);
    }
    -(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2{
        
        return [str1 stringByAppendingString:str2];
    }
    @end
    
    方法实现
    -(void)exchangeAttribute{
        Person *p = [[Person alloc]init];
        p.height = @"178";
        NSLog(@"身高==%@",p.height);
    }
    

    打印结果

    2016-10-24 10:45:09.003 WsBlog[11181:4616582] 身高==178
    

    2.动态控制变量

    -(void)controlVariables{
        Person * p = [Person new];
        p.name = @"wym";
        NSLog(@"%@",[p name]);
        unsigned int count;
        //Ivar表示类中的实例变量。Ivar其实就是一个指向objc_ivar结构体指针,它包含了变量名(ivar_name)、变量类型(ivar_type)等信息。
        Ivar *ivar = class_copyIvarList([Person class], &count);
        for (int i = 0; i < count; i ++) {
            Ivar var = ivar[i];
            const char *varName = ivar_getName(var);
            NSString *name = [NSString stringWithCString:varName encoding:NSUTF8StringEncoding];
            if ([name isEqualToString:@"_name"]) {
                object_setIvar(p, var, @"ws");
                break;
            }
        }
        NSLog(@"%@",p.name);
    }
    

    打印结果

    2016-10-24 10:45:09.004 WsBlog[11181:4616582] wym
    2016-10-24 10:45:09.004 WsBlog[11181:4616582] ws
    

    3.利用runtime动态遍历一个类的全部成员变量

    -(void)getAttribute{
        //1.导入头文件 <objc/runtime.h>
        unsigned int count = 0;
        //获取指向该类所有属性的指针
        objc_property_t *propeprties = class_copyPropertyList([Person class], &count);
        for (int i = 0; i < count; i++) {
            //获得
            objc_property_t property = propeprties[i];
            //根据objc_property_t 获取所有属性的名称--->C语言的字符串
            const char *name = property_getName(property);
            NSString *attributeName = [NSString stringWithUTF8String:name];
            NSLog(@"%d-----%@",i,attributeName);
        }
    }
    

    打印结果

    2016-10-24 10:45:09.003 WsBlog[11181:4616582] 0-----height
    2016-10-24 10:45:09.003 WsBlog[11181:4616582] 1-----name
    2016-10-24 10:45:09.004 WsBlog[11181:4616582] 2-----gender
    2016-10-24 10:45:09.004 WsBlog[11181:4616582] 3-----age
    

    4.动态添加方法

    void goHome(id self, SEL _cmd){
        NSLog(@"回家");
    }
    
    - (void)addMethod
    {
        Person *p = [Person new];
        p.name = @"ET";
        
        class_addMethod([Person class], @selector(shise), (IMP)goHome, "v@:");
        
        [p performSelector:@selector(shise) withObject:nil];
    }
    
    

    打印结果

    2016-10-24 10:45:09.004 WsBlog[11181:4616582] 回家
    

    5.动态交换方法实现

    -(void)exchangeMethod{
        Person *p = [[Person alloc]init];
        p.name = @"ET";
        [p eat];
        [p play];
        // 实现方法交换
        Method m1 = class_getInstanceMethod([Person class], @selector(eat));
        Method m2 = class_getInstanceMethod([Person class], @selector(play));
        method_exchangeImplementations(m1, m2);
        [p eat];
        [p play];
    }
    

    打印结果

    2016-10-24 10:45:09.004 WsBlog[11181:4616582] ET玩
    2016-10-24 10:45:09.005 WsBlog[11181:4616582] ET吃饭
    2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET吃饭
    2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET玩
    

    6.动态调取方法

    -(void)likePlay{
        NSLog(@"喜欢玩");
    }
    

    打印结果

    2016-10-24 10:45:09.003 WsBlog[11181:4616582] 喜欢玩
    

    http://www.jianshu.com/p/e04e66908b09

    相关文章

      网友评论

      本文标题:iOS-Runtime原理及使用

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