runtime运行时常用方法

225 阅读2分钟

引入头文件#import <objc/runtime.h>

常见runtime api

  • object_getClass 获取class

    • Class objClass = object_getClass([NSObject alloc]);
  • class_getName(Class _Nullable cls) 获取类名 传入class

    • const char *className = class_getName(objClass);
  • objc_getMetaClass(const char * _Nonnull name) 获取元类 传入class名

    • Class metaClass = objc_getMetaClass(className);
  • class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name) 获取实例方法

    • Method instanceMethod = class_getInstanceMethod(objClass, @selector(xxInstanceMethod));
  • class_getClassMethod(Class _Nullable cls, SEL _Nonnull name) //获取类方法

    • Method classMethod = class_getClassMethod(metaClass, @selector(xxClassMethod));
    • 元类也返回类方法,和类方法地址一样
    • 源码如下:
      Method class_getClassMethod(Class cls, SEL sel)
      {
          if (!cls  ||  !sel) return nil;
          return class_getInstanceMethod(cls->getMeta(), sel);
      }
      
      Class getMeta() {
          if (isMetaClassMaybeUnrealized()) return (Class)this;//判断是元类就返回 避免查询递归
          else return this->ISA();
      }
      
  • SEL method_getName(Method m) 从Method获取sel名

  • Method class_copyMethodList(Class cls, unsigned int outCount) //获取类cls的方法

    • 示例:
       //打印Class pClass的实例方法
       void objc_copyMethodList(Class pClass){
            unsigned int count = 0;
            Method *methods = class_copyMethodList(pClass, &count);
            NSLog(@"----------------");           
            NSLog(@"%s",__func__);
            for (unsigned int i=0; i < count; i++) {
                Method const method = methods[i];
                //获取方法名
                NSString *key = NSStringFromSelector(method_getName(method));
                NSLog(@"%@实例方法: %@", pClass,key);
            }
            free(methods);
       }      
      
  • IMP class_getMethodImplementation(Class cls, SEL sel) 获取方法实现指针

    • Class pClass = object_getClass([NSObject alloc]);IMP imp = class_getMethodImplementation(pClass, @selector(xxInstanceMethod));
    • 源码:
      IMP class_getMethodImplementation(Class cls, SEL sel)
      {
          IMP imp;
          if (!cls  ||  !sel) return nil;
          ...
          imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
      
          // Translate forwarding function to C-callable external version
          if (!imp) { //如果找不到(没有这个方法或者只声明未实现)就会找消息转发_objc_msgForward
              return _objc_msgForward;
          }
      
          return imp;
      }
      
  • const char *ivar_getName(Ivar ivar) 获取实例变量名

  • Ivar *class_copyIvarList(Class cls, unsigned int *outCount) 获取成员变量列表

  • objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) 获取属性列表

    • 示例:
      //获取成员变量和属性
      void objc_copyIvar_copyProperies(Class pClass){
         unsigned int count = 0;
         Ivar *ivars = class_copyIvarList(pClass, &count);
         for (unsigned int i=0; i < count; i++) {
             Ivar const ivar = ivars[i];
             //获取实例变量名
             const char*cName = ivar_getName(ivar);
             NSString *ivarName = [NSString stringWithUTF8String:cName];
             LGLog(@"class_copyIvarList:%@",ivarName);
         }
         free(ivars);
      
         unsigned int pCount = 0;
         objc_property_t *properties = class_copyPropertyList(pClass, &pCount);
         for (unsigned int i=0; i < pCount; i++) {
             objc_property_t const property = properties[i];
             //获取属性名
             NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
             //获取属性值
             LGLog(@"class_copyProperiesList:%@",propertyName);
         }
         free(properties);
      }
      
  • const char *ivar_getTypeEncoding(Ivar ivar) 获取对应的编码。详细参见Type Encodings

  • const char *property_getName(objc_property_t prop) 获取属性名

  • const char *property_getAttributes(objc_property_t prop) 获取属性真实类型

    • 举例:
      //Person.h
      @property (nonatomic, copy) NSString *nickName;
      
      //使用
      Class pClass = Person.class;
      unsigned int outCount, i;
      objc_property_t *properties = class_copyPropertyList(pClass, &outCount);
      for (i = 0; i < outCount; i++) {
          objc_property_t property = properties[i];
          fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
      }
      
      打印:nickName T@"NSString",C,N,V_nickName
      说明:T: 在大写 T 后面是放的是该属性的数据类型 NSString;
      C : copy;
      N : nonatomic;
      V: 在大写 V 后面放的是该属性的变量名称(因为我们知道 @property 实际上只是为我们编写好了 getter 和 setter 方法,并创建一个以下划线开头的变量_nickName);
      详细参见官方文档.
  • SEL sel_registerName(const char * _Nonnull str) //获取sel