美文网首页
Runtime的使用

Runtime的使用

作者: 超级卡布达 | 来源:发表于2018-12-19 15:45 被阅读279次

    Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的。比如:

    id objc = [NSObject alloc]
    objc = [objc init]
    

    类方法本质:类对象调用[NSObject class]
    id:谁发送消息
    SEL: 发送什么消息
    苹果运行使用objc_msgSend,如没有提示则到build setting搜索msg改为no
    底层运行时会转化成发送消息

    id objc = objc_msgSend(objc_getClass("NSObject"),sel_registerName("alloc"));
    objc = objc_msgSend(objc,sel_registerName("init"));
    

    最终生成消息机制,编译器做的事
    最终代码,需要把当前代码重新编译,用code编译器,clang
    clang -rewrite-objc 文件名

    开发中runtime的使用场景:1.不得不用runtime消息机制,可以帮我们调用私有方法。2.runtime一般都是针对系统的类
    方法调用流程

    怎么去调用方法,对象方法:类对象的方法列表,类方法:元类中方法列表
    1.通过isa指针去对应的类中查找
    2.注册方法编号
    3.根据方法编号去查找对应的方法
    4.找到的只是最终函数实现地址,根据地址去方法去调用方法

    内容五大区:栈、堆、静态区、常量区、方法区

    1.栈:不需要手动管理内存,自动管理
    2.堆:需要手动管理内存,自己去释放

    method函数的解析

    SEL selector 的简写,俗称方法选择器,实质存储的是方法的名称
    IMP implement 的简写,俗称方法实现,看源码得知它就是一个函数指针
    Method 对上述两者的一个包装结构.

    //判断类中是否包含某个方法的实现
      BOOL class_respondsToSelector(Class cls, SEL sel)
      //获取类中的方法列表
      Method *class_copyMethodList(Class cls, unsigned int *outCount) 
      //为类添加新的方法,如果方法该方法已存在则返回NO
      BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
      //替换类中已有方法的实现,如果该方法不存在添加该方法
      IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) 
      //获取类中的某个实例方法(减号方法)
      Method class_getInstanceMethod(Class cls, SEL name)
      //获取类中的某个类方法(加号方法)
      Method class_getClassMethod(Class cls, SEL name)
      //获取类中的方法实现
      IMP class_getMethodImplementation(Class cls, SEL name)
      //获取类中的方法的实现,该方法的返回值类型为struct
      IMP class_getMethodImplementation_stret(Class cls, SEL name) 
      //获取Method中的SEL
      SEL method_getName(Method m) 
      //获取Method中的IMP
      IMP method_getImplementation(Method m)
      //获取方法的Type字符串(包含参数类型和返回值类型)
      const char *method_getTypeEncoding(Method m) 
      //获取参数个数
      unsigned int method_getNumberOfArguments(Method m)
      //获取返回值类型字符串
      char *method_copyReturnType(Method m)
      //获取方法中第n个参数的Type
      char *method_copyArgumentType(Method m, unsigned int index)
      //获取Method的描述
      struct objc_method_description *method_getDescription(Method m)
      //设置Method的IMP
      IMP method_setImplementation(Method m, IMP imp) 
      //替换Method
      void method_exchangeImplementations(Method m1, Method m2)
    
      //获取SEL的名称
      const char *sel_getName(SEL sel)
      //注册一个SEL
      SEL sel_registerName(const char *str)
      //判断两个SEL对象是否相同
      BOOL sel_isEqual(SEL lhs, SEL rhs) 
    
      //通过块创建函数指针,block的形式为^ReturnType(id self,参数,...)
      IMP imp_implementationWithBlock(id block)
      //获取IMP中的block
      id imp_getBlock(IMP anImp)
      //移出IMP中的block
      BOOL imp_removeBlock(IMP anImp)
    
      //调用target对象的sel方法
      id objc_msgSend(id target, SEL sel, 参数列表...)
    
    动态添加方法class_addMethod
    //resolveInstanceMethod对应的对象方法,resolveClassMethod对应的是类方法
    //什么时候调用:只要一个对象调用了一个来实现的方法就就调用这个方法,进行处理
    //作用:动态添加方法,处理为实现的方法
    //class :给那个类添加方法
    //SEL:添加那个方法
    //IMP:implementation方法实现->函数->函数入口->函数名
    //type:方法类型
    + (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == NSSelecterFromString(@"run:"))
        class_addMethod(self, sel, (IMP)aaa,"v@:@");
        return YES;
    }
     
    //任何方法默认都有两个隐式参数,self,_cmd
    void aaa(id self,SEL _cmd,NSNumber *num) {
        NSLog(@"跑了%@米",num);
    }
    

    TypeEncoding表


    TypeEncoding
    动态添加属性
    @interface NSObject (JHObject)
    //@property分类:只会生成set,get方法声明,不会生成实现,也不会生成下划线成员属性
    @property NSString *name;
    @end
    
    @implementation NSObject (JHObject)
    
    -(void)setName:(NSString *)name{
        //object:给那个对象添加属性
    //    key 属性名称
    //    value 属性值
    //    policy 保存策略
    //    objc_setAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>, <#id  _Nullable value#>, <#objc_AssociationPolicy policy#>)
        objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY);
    }
    -(NSString *)name{
        return objc_getAssociatedObject(self, "name");
    }
    @end
    
    交换方法

    使用场景:当我们需要在系统方法里做事情时
    示例:修改系统默认字体

    //把类加载进内存的时候调用,只会调用一次
    +(void)load {
    //    系统方法
        Method fun1 = class_getClassMethod(self, @selector(systemFontOfSize:));
    //    自定义UIFont字体类型的方法
        Method fun2 = class_getClassMethod(self, @selector(jh_systemFontOfSize:));
    //    交换方法1和方法2
        method_exchangeImplementations(fun1, fun2);
    
    }
    + (UIFont *)jh_systemFontOfSize:(CGFloat)size{
        UIFont *font = [UIFont fontWithName:@"Helvetica-Bold" size:size];
        return font;
    }
    

    代码示例

    备注:

    如果有不足或者错误的地方还望各位读者批评指正,可以评论留言,笔者收到后第一时间回复。

    QQ/微信:976971956/ljh976971956。

    简书号:超级卡布达

    感谢各位观众老爷的阅读,如果觉得笔者写的还凑合,可以关注或收藏一下,不定期分享一些好玩的实用的demo给大家。

    文/超级卡布达(简书作者)

    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

    相关文章

      网友评论

          本文标题:Runtime的使用

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