Runtime相关方法

作者: Maj_sunshine | 来源:发表于2018-08-06 19:00 被阅读32次

    每个人的学习方式不同,我习惯于先了解每个方法的使用方式是什么,方法是做什么用的。今天的runtime也是。我们可以从官方文档中找出runtime的所有方法


    类相关的方法

    在文档中我们可以看到类相关的所有方法。


    官方文档runtime class相关.gif

    顺便做个整理

    class_get

    class_get相关.gif
    • (了解) class_getName (获取类名) ,返回值类型const char *
     // 获取类名 (获取的是const char 类型数据)
        NSLog(@"类名 :%s",class_getName([UILabel class]));
    

    有点类似NSStringFromClass,不过NSStringFromClass返回的是NSString

    • (了解) class_getSuperclass(获取一个类的父类),返回值类型class
    // 获取父类
        NSLog(@"父类 : %@",class_getSuperclass([UILabel class]));
    

    NSObject里提供了一个superclass的只读属性,也可以获取父类。

    • (了解) class_getProperty ,(获取指定的属性),返回值类型objc_property类型结构体
    objc_property_t property = class_getProperty([UILabel class], "text");
         // 打印一下获取的属性是什么 ,通过property_getName
    NSString *propertyString = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
    NSLog(@"取出的属性 = %@",propertyString);
    
    • (了解)class_getVersion,(获取版本号),返回值类型int
    NSLog(@"版本号 = %d", class_getVersion([UILabel class]));
    
    • (了解)class_getImageName,(获取类坐在的动态库位置),返回类型const char *
    NSLog(@"获取类坐在的动态库位置 = %s", class_getImageName([UILabel class]));
    
    • (重要)class_getClassMethod,(获取类方法),返回类型Method
    Method method = class_getClassMethod([UILabel class], @selector(userInterfaceLayoutDirectionForSemanticContentAttribute:));
    NSLog(@"方法名 = %s",sel_getName(method_getName(method)));
    
    • (重要)class_getInstanceMethod,(获取实例方法),返回类型Method
     Method instanceMethod = class_getInstanceMethod([UILabel class], @selector(setBackgroundColor:));
    NSLog(@"实例方法名 = %s",sel_getName(method_getName(instanceMethod)));
    
    • (了解)class_getClassVariable,(获取类的成员变量信息),返回类型Ivar
    Ivar ivar = class_getClassVariable([Person class], "_sex");
    
    • (重要)class_getMethodImplementation,(获取实例方法),返回类型IMP
    IMP imp = class_getMethodImplementation([UILabel class], @selector(setBackgroundColor:));
    
    • (了解)class_getInstanceSize,(获取实例对象大小),返回类型size_t
    size_t size = class_getInstanceSize([UILabel class]);
        NSLog(@"实例对象大小 = %li",size);
    
    • (了解)class_getIvarLayout([UILabel class]) class_getWeakIvarLayout([UILabel class]),(获取类的成员变量信息),返回类型const uint8_t *可以参考这篇

    • 输出

    2018-08-02 18:36:31.060785+0800 runtime[27722:927392] 类名 :UILabel
    2018-08-02 18:36:31.060988+0800 runtime[27722:927392] 类名 :UILabel
    2018-08-02 18:36:31.061228+0800 runtime[27722:927392] 父类 : UIView
    2018-08-02 18:36:31.064525+0800 runtime[27722:927392] 取出的属性 = text
    2018-08-02 18:36:31.064713+0800 runtime[27722:927392] 版本号 = 0
    2018-08-02 18:36:31.064841+0800 runtime[27722:927392] 获取类坐在的动态库位置 = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/UIKit.framework/UIKit
    2018-08-02 18:36:31.064974+0800 runtime[27722:927392] 方法名 = userInterfaceLayoutDirectionForSemanticContentAttribute:
    2018-08-02 18:36:31.065233+0800 runtime[27722:927392] 实例方法名 = setBackgroundColor:
    2018-08-02 18:36:31.065715+0800 runtime[27722:927392] 实例对象大小 = 728
    

    class_copy

    class_copy相关.gif
    • (重要)class_copyIvarList,(获取类的实例变量列表),返回类型Ivar *
      获取类的实例变量列表
    unsigned int count = 0;
    Ivar * varList = class_copyIvarList([UILabel class], &count);;
    for (int i = 0; i<count; i++) {
         NSLog(@"%s",ivar_getName(varList[i]));
    }
     //释放varList
    free(varList);
    
    • (重要)class_copyMethodList,(获取类的所有方法),返回类型Method *
      获取类的所有方法
    unsigned int count = 0;
        Method *method = class_copyMethodList([UILabel class], &count);;
        for (int i = 0; i<count; i++) {
            NSLog(@"%s",sel_getName(method_getName(method[i])));
        }
    //释放varList
        free(method);
    
    • (重要)class_copyPropertyList,(获取类的属性列表),返回类型objc_property_t *
      获取属性列表
    unsigned int count = 0;
    objc_property_t *property = class_copyPropertyList([UILabel class], &count);;
        for (int i = 0; i<count; i++) {
            NSLog(@"%s",property_getName(property[i]));
        }
        //释放varList
        free(property);
    
    • (重要)class_copyProtocolList,(获取类的协议列表),返回类型Protocol * __unsafe_unretained *
    Protocol * __unsafe_unretained *protocol = class_copyProtocolList([UITableViewController class], &count);;
        for (int i = 0; i<count; i++) {
            Protocol *pro = protocol[I];
            NSLog(@"%@",NSStringFromProtocol(pro));
        }
        //释放varList
        free(protocol);
    

    因为上面的几个方法打印的东西太长,就不输出了。

    class_add

    class_add相关.gif
    • (了解)class_addIvar,(为类动态添加实例变量),返回类型BOOL
    class_addIvar([Person class], "addLength", sizeof(NSInteger), log2(_Alignof(NSInteger)), @encode(NSInteger));
    
    • (重要)class_addMethod,(为类动态添加方法),返回类型BOOL
      这里说重要注意是因为method swizzle
    // 取得函数名称
        SEL originSel = @selector(setText:);
        SEL swizzleSel = @selector(swizzleSetText:);
        Method originMethod = class_getInstanceMethod(class, originSel);
        Method swizzleMethod = class_getInstanceMethod(class, swizzleSel);
    
    // 添加方法
        BOOL addMethod = class_addMethod(class, originSel, method_getImplementation(swizzleMethod),method_getTypeEncoding(swizzleMethod));
    
    • (了解)class_addProperty,(为类动态添加属性),返回类型BOOL
      我们开发中一般用关联对象添加属性。
    objc_property_attribute_t type = { "T", "@\"NSString\"" };//属性类型为NSString
        objc_property_attribute_t ownership = { "C", "copy" }; // C = copy
        objc_property_attribute_t backingivar  = { "V", "_personName" };
        objc_property_attribute_t attrs[] = { type, ownership, backingivar };
        class_addProperty([Person class], "personName", attrs, 3);
    
    • (了解)class_addProtocol,(为类动态添加属性),返回类型BOOL
    class_addProtocol(<#Class  _Nullable __unsafe_unretained cls#>, <#Protocol * _Nonnull protocol#>)
    

    class_replace

    class_replace相关.gif
    • (重要)class_replaceMethod,(为类替换方法)
    class_replaceMethod(class, swizzleSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    
    • (了解)class_replaceProperty,(替换类的属性)
    void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    

    class_conformsTo

    class_ conform相关.gif
    • (了解)class_conformsToProtocol,(类是否实现指定的协议) ,返回值类型(BOOL)
     class_conformsToProtocol ( Class cls, Protocol *protocol );
    

    实际开发我们一般用NSObject的- (BOOL)conformsToProtocol:(Protocol *)aProtocol;方法。

    class_respondsTo

    class_respond相关.gif
    • (了解)** class_respondsToSelector**,(是否可以响应方法) ,返回值类型(BOOL)
    class_respondsToSelector(<#Class  _Nullable __unsafe_unretained cls#>, <#SEL  _Nonnull sel#>)
    

    实际开发我们一般用NSObject的- (BOOL)respondsToSelector:(SEL)aSelector;方法。


    objc_ 和 object_

    • objc_ 所有方法


      官方文档runtime objc_相关.gif
    • object_所有方法


      屏幕快照 2018-08-03 下午3.01.26.png

    objc_get

    屏幕快照 2018-08-03 下午1.56.53.png
    • (重要)objc_getClass,(获取对象的类) ,返回值类型 Class
    NSLog(@"%@",objc_getClass("Person"));
    

    输出

    2018-08-03 15:26:46.212256+0800 runtime[30988:1216350] Person
    

    在实际开发中我们一般用NSClassFromString()来通过类名获取一个类

    • (重要)object_getClass,(获取一个类isa指针指向的类) ,返回值类型 Class
      !!!注意这个方法要和上面区分开,这是用来获取isa指针指向的类,如果不知道isa指针的同学自己去百度
    Class metaClass = object_getClass([Person class]);
    NSLog(@"%@", class_isMetaClass(metaClass) ? @"是元类" : @"不是元类");
    NSLog(@"%@", class_isMetaClass([Person class]) ? @"是元类" : @"不是元类");
        
    NSLog(@"Person类的isa指向%@",object_getClass([Person class]));
    NSLog(@"Person元类的isa指向%@",object_getClass(object_getClass([Person class])));
    NSLog(@"NSObject元类的isa指向%@",object_getClass(object_getClass(object_getClass([Person class]))));
    NSLog(@"NSObject元类的父类 = %@",class_getSuperclass(object_getClass(object_getClass([Person class]))));
    NSLog(@"NSObject元类的父类的父类 = %@",class_getSuperclass(class_getSuperclass(object_getClass(object_getClass([Person class])))));
    

    输出

    2018-08-03 16:00:14.819770+0800 runtime[31283:1243260] 是元类
    2018-08-03 16:00:14.819992+0800 runtime[31283:1243260] 不是元类
    2018-08-03 16:00:14.820157+0800 runtime[31283:1243260] Person类的isa指向Person
    2018-08-03 16:00:14.820287+0800 runtime[31283:1243260] Person元类的isa指向NSObject
    2018-08-03 16:00:14.820417+0800 runtime[31283:1243260] NSObject元类的isa指向NSObject
    2018-08-03 16:00:14.820518+0800 runtime[31283:1243260] NSObject元类的父类 = NSObject
    2018-08-03 16:00:14.820645+0800 runtime[31283:1243260] NSObject元类的父类的父类 = (null)
    

    我们可以看出 object_getClass方法是获取一个类的元类,Person类的isa指针指向Person元类,Person元类的isa指针指向NSObject元类,NSObject元类的isa指向自己,形成了一个闭环。并且NSObject元类的父类是NSObject,NSObject的父类为null
    是不是想起了一张图

    449095-3e972ec16703c54d.png
    • (了解)objc_getMetaClass,(获取类的元类) ,返回值类型Class *
    • (了解)object_getClassName,(获取类的元类名称) ,返回值类型const char *

    区别于object_getClass获取元类,objc_getMetaClass获取元类用的是c字符串。既然object_getClass是获取一个对象的元类对象,那么object_getClassName一个猜想的出来是获取元类对象的名称。

    NSLog(@"Person类的元类 = %@",objc_getMetaClass("Person"));
    NSLog(@"Person元类的元类的名称 = %s",object_getClassName(objc_getMetaClass("Person")));
    NSLog(@"Person元类的isa指针指向 = %@",objc_getMetaClass(object_getClassName(objc_getMetaClass("Person"))));
    

    输出

    2018-08-03 16:14:49.051873+0800 runtime[31357:1254499] Person类的isa指针 = Person
    2018-08-03 16:14:49.052081+0800 runtime[31357:1254499] Person元类名称 = NSObject
    2018-08-03 16:14:49.052217+0800 runtime[31357:1254499] Person元类的isa指针指向 = NSObject
    
    • (了解)objc_getProtocol,(获取一个协议) ,返回值类型Protocol *
    Protocol *protocol =  objc_getProtocol("PersonDelegate");
    

    这个在实际开发中就是@protocol(PersonDelegate)

    • (了解)objc_getClassList,(获取类列表)
      我们可以用这个方法来打印一个类所有的子类
    int numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
        Class *classes = NULL;
        while (numClasses < newNumClasses) {
            numClasses = newNumClasses;
            classes = (Class *)realloc(classes, sizeof(Class) * numClasses);
            newNumClasses = objc_getClassList(classes, numClasses);
            
            for (int i = 0; i < numClasses; i++) {
                const char *className = class_getName(classes[i]);
                if (class_getSuperclass(classes[i]) == [UILabel class]) {
                    NSLog(@"%s" , className);
                }
            }
            
        }
        free(classes);
    

    输出UILabel的所有子类对象。

    2018-08-03 16:45:45.430312+0800 runtime[31498:1276113] _MKUILabel
    2018-08-03 16:45:45.430450+0800 runtime[31498:1276113] _UITableViewHeaderFooterViewLabel
    2018-08-03 16:45:45.430567+0800 runtime[31498:1276113] _UIActivityGroupActivityCellTitleLabel
    2018-08-03 16:45:45.430899+0800 runtime[31498:1276113] UITabBarButtonLabel
    2018-08-03 16:45:45.431003+0800 runtime[31498:1276113] UITableViewLabel
    2018-08-03 16:45:45.431205+0800 runtime[31498:1276113] UITextFieldLabel
    2018-08-03 16:45:45.431304+0800 runtime[31498:1276113] UIButtonLabel
    2018-08-03 16:45:45.431396+0800 runtime[31498:1276113] UIDateLabel
    2018-08-03 16:45:45.431498+0800 runtime[31498:1276113] UITextLabel
    2018-08-03 16:45:45.431594+0800 runtime[31498:1276113] UISegmentLabel
    
    • (了解)objc_getRequiredClass,(返回一个类,要是没有这个类就去除这个类 ) ,返回值类型Protocol *
      !!! 要设置Build Phase——》Compile Sources相应文件ARC转非ARC-fno-objc-arc;才能支持objc_getRequiredClass

    • (重要)objc_getAssociatedObject,(关联对象get) ,返回值类型Protocol *

    - (UILabel *)badge {
        return objc_getAssociatedObject(self, _cmd);
    }
    
    - (void)setBadge:(UILabel *)label {
        objc_setAssociatedObject(self, @selector(badge), label, OBJC_ASSOCIATION_RETAIN);
    }
    

    这里个人喜欢用@selector()即当前方法选择子来代替关键字。

    • (了解)object_getIvar,(获取实例变量的值) ,返回值类型id*
    _person = [[Person alloc] init];
     _person.name = @"小妹";
    // 获取_person实例对象中的name实例变量的值
    NSString *name = object_getIvar(_person, class_getInstanceVariable([Person class], "_name"));
    NSLog(@"name = %@",name);
    

    输出

    2018-08-03 17:51:48.294600+0800 runtime[33733:1321519] name = 小妹
    

    objc_copy

    • (了解)objc_copyClassList ,返回值类型Class _Nonnull *
      获得已经注册的所有的类,下面打印UIScrollView的所有子类。
    unsigned int outCount;
        Class *classes = objc_copyClassList(&outCount);
        for (int i = 0; i < outCount; i++) {
            @autoreleasepool {
                if (class_getSuperclass(classes[i]) == [UIScrollView class]) {
                    NSLog(@"%s",class_getName(classes[i]));
                }
            }
        }
        free(classes);
    

    输出

    2018-08-05 19:32:34.376451+0800 runtime[37322:1424135] _MKPlacePhotoView
    2018-08-05 19:32:34.376782+0800 runtime[37322:1424135] NUIContentScrollView
    2018-08-05 19:32:34.376940+0800 runtime[37322:1424135] _UIInterfaceActionRepresentationsSequenceView
    2018-08-05 19:32:34.377093+0800 runtime[37322:1424135] _UIQueuingScrollView
    2018-08-05 19:32:34.377196+0800 runtime[37322:1424135] _UIAlertControllerShadowedScrollView
    2018-08-05 19:32:34.377307+0800 runtime[37322:1424135] _UICompatibilityTextView
    2018-08-05 19:32:34.377404+0800 runtime[37322:1424135] UIPrinterSetupPINScrollView
    2018-08-05 19:32:34.377599+0800 runtime[37322:1424135] UITextView
    2018-08-05 19:32:34.377743+0800 runtime[37322:1424135] UIWebOverflowScrollView
    2018-08-05 19:32:34.377845+0800 runtime[37322:1424135] UIPageControllerScrollView
    2018-08-05 19:32:34.378044+0800 runtime[37322:1424135] UIWebScrollView
    2018-08-05 19:32:34.378150+0800 runtime[37322:1424135] UIFieldEditor
    2018-08-05 19:32:34.378248+0800 runtime[37322:1424135] UITableView
    2018-08-05 19:32:34.378335+0800 runtime[37322:1424135] UITableViewWrapperView
    2018-08-05 19:32:34.378437+0800 runtime[37322:1424135] UICollectionView
    
    • (了解)objc_copyImageNames,(获取所有加载的Objective-C框架和动态库的名称) ,返回值类型const char * _Nonnull *

    • (了解)objc_copyProtocolList,(获取运行时所知道的所有协议的数组) ,返回值类型Protocol * __unsafe_unretained _Nonnull *

    • (了解)objc_copyClassNamesForImage,(获取指定库或框架中所有类的类名) ,返回值类型const char * _Nonnull *

    unsigned int outCount;
        const char ** classes = objc_copyClassNamesForImage(class_getImageName(NSClassFromString(@"UIView")), &outCount);
        for (int i = 0; i < outCount; i++) {
            NSLog(@"class name: %s", classes[i]);
        }
        free(classes);
    

    objc_set

    • (重要)objc_setAssociatedObject,(设置关联对象)
     objc_setAssociatedObject(id  _Nonnull object, //关联对象
                                 const void * _Nonnull key, // 关联对象标识符key,我通常用@selector()作为标识符
                                 id  _Nullable value, // 关联对象的值
                                 objc_AssociationPolicy policy) // 关联对象的内存管理语义
    
    1. objc_AssociationPolicy是一个枚举
      OBJC_ASSOCIATION_ASSIGN 等价于 @property(assign)。
      OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于 @property(strong, nonatomic)。
      OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)。
      OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)。
      OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)

    object_set

    • (重要)object_setIvar,(设置实例变量的值)
    _person = [[Person alloc] init];
    _person.name = @"小妹";
    object_setIvar(_person, class_getInstanceVariable([Person class], "_name"),@"新名字");
    NSLog(@"name = %@",_person.name);
    

    输出

    2018-08-05 20:29:36.249324+0800 runtime[37441:1457957] name = 新名字
    
    • (重要)object_setClass,(设置对象的isa指向)
      !!! 类对象中存储着实例对象的实例方法,元类对象中存储着类的类方法。如果改变isa指向,会导致本来是对A类的方法缓存或方法列表中查找Method,变成从B类中查找Method。
    @interface Person : NSObject
    // 在Person .h文件中,有eat方法
    - (void)eat:(NSString *)foodName;
    
    @end
    
    @implementation Person
    
    - (instancetype)init {
        if (self = [super init]) {
     // 改变isa指针指向Animal类
            object_setClass(self, [Animal class]);
        }
        return self;
    }
    
    // 人吃食物
    - (void)eat:(NSString *)foodName {
        NSLog(@"人吃食物 : %@",foodName);
    }
    
    @end
    
    @interface Animal : NSObject
    
    - (void)eat:(NSString *)foodName;
    
    @end
    
    @implementation Animal
    
    - (void)eat:(NSString *)foodName {
        NSLog(@"动物吃食物 : %@",foodName);
    }
    
    @end
    

    调用方法

    _person = [[Person alloc] init];
    [_person eat:@"香蕉"];
    

    输出

    2018-08-05 20:38:18.353851+0800 runtime[37495:1465311] 动物吃食物 : 香蕉
    

    所以真正调用方法的类并不一定是代码中调用方法的那个类,最终和运行时对象的isa指向有关。

    • (了解)object_setIvarWithStrongDefault,(设置实例变量的值)
    _person = [[Person alloc] init];
    _person.name = @"小妹";
    object_setIvarWithStrongDefault(_person, class_getInstanceVariable([Person class], "_name"),@"新名字");
    NSLog(@"name = %@",_person.name);
    输出
    
    2018-08-05 20:53:05.701262+0800 runtime[37528:1475141] name = 新名字
    

    创建销毁类

    • (重要)** objc_allocateClassPair**,(创建一个类)
    • (重要)** objc_registerClassPair**,(注册一个类)
    • (重要)** objc_disposeClassPair**,(销毁一个类)
      runtime能在运行时动态添加一个类
     // 创建一个类
        Class newClass =  objc_allocateClassPair([Person class], "Man", 0);
         // 方法
        Method method = class_getInstanceMethod([self class], @selector(buyClothes));
         // 为类添加一个方法
        class_addMethod(newClass, method_getName(method), method_getImplementation(method), method_getTypeEncoding(method));
         // 注册类
        objc_registerClassPair(newClass);
         // 创建类的实例对象 alloc
       id newInstance = class_createInstance(newClass, sizeof(unsigned));
         // init
       id hangzhouMan = [newInstance init];
         // 调用方法
       [hangzhouMan performSelector:@selector(buyClothes) withObject:nil];
    

    创建类并调用方法,输出

    2018-08-05 21:21:43.576871+0800 runtime[37627:1495822] 男人买衣服
    

    销毁

    objc_disposeClassPair(newClass);
      // 调用方法
    [hangzhouMan performSelector:@selector(buyClothes) withObject:nil]
    

    销毁之后调用方法,出现EXC_BAD_ACCESS


    ivar(实例变量)

    先看看ivar在底层的数据结构

    typedef struct objc_ivar *Ivar;
    
    struct objc_ivar {
        char *ivar_name                 OBJC2_UNAVAILABLE;  // 变量名
        char *ivar_type                 OBJC2_UNAVAILABLE;  // 变量类型
        int ivar_offset                 OBJC2_UNAVAILABLE;  // 基地址偏移字节
    #ifdef __LP64__
        int space                       OBJC2_UNAVAILABLE;
    #endif
    }
    

    所有我们就能知道ivar通过runtime能获得的变量

    • (重要)ivar_getName,(获取实例变量名) ,返回值类型const char *
    • (重要)ivar_getOffset,(获取实例基地址偏移字节) ,返回值类型int
    • (重要)ivar_getTypeEncoding,(获取实例变量类型) ,返回值类型const char *
      结合上面介绍的
    • class_addIvar ,(添加一个实例变量)
    • class_getInstanceVariable ,(获取实例变量)
    • object_setIvarWithStrongDefault ,(为实例变量赋值)
    • object_setIvar ,(为实例变量赋值)
    • object_getIvar ,(获取实例变量的值)
    • class_copyIvarList ,(获取类的实例变量列表)

    我来创建一个类,并在类中添加实例变量,赋值并打印。

      // 创建一个类newClass继承Person
        Class newClass =  objc_allocateClassPair([Person class], "Man", 0);
         // 添加实例变量_skinColor
        BOOL flag1 = class_addIvar(newClass, "_skinColor", sizeof(NSString*), log2(sizeof(NSString *)), @encode(NSString *));
        if (flag1) {
            NSLog(@"NSString*类型  _skinColor变量添加成功");
        }
         // 注册这个类
        objc_registerClassPair(newClass);
         // 获取类的实例变量_skinColor
        Ivar colorIvar = class_getInstanceVariable(newClass, "_skinColor");
         // 创建实例对象instance
        id instance = [class_createInstance(newClass, sizeof(unsigned)) init];
         // 为这个实例对象的_skinColor赋值为黄色
        object_setIvar(instance, colorIvar, @"黄色");
         // 打印
        NSLog(@"肤色skinColor = %@",object_getIvar(instance, colorIvar));
        
         // 打印实例变量列表
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList(newClass, &count);
        for (int i = 0; i < count; i++) {
            Ivar ivar = ivarList[i];
            NSLog(@"实例变量name = %s",ivar_getName(ivar));
            NSLog(@"实例变量变量类型type = %s",ivar_getTypeEncoding(ivar));
            NSLog(@"实例变量地址偏移name = %td",ivar_getOffset(ivar));
        }
    

    输出

    2018-08-06 10:43:30.631866+0800 runtime[42814:1664021] NSString*类型  _skinColor变量添加成功
    2018-08-06 10:43:30.632097+0800 runtime[42814:1664021] 肤色skinColor = 黄色
    2018-08-06 10:43:30.632235+0800 runtime[42814:1664021] 实例变量name = _skinColor
    2018-08-06 10:43:30.632406+0800 runtime[42814:1664021] 实例变量变量类型type = @
    2018-08-06 10:43:30.632506+0800 runtime[42814:1664021] 实例变量地址偏移name = 32
    

    Method

    先看看Method在底层的数据结构

    typedef struct objc_method *Method;
    
    struct objc_method {
        SEL method_name                 OBJC2_UNAVAILABLE;  // 方法名
        char *method_types                  OBJC2_UNAVAILABLE; // 参数类型
        IMP method_imp                      OBJC2_UNAVAILABLE;  // 方法实现
    }
    

    所有我们就能知道Method通过runtime能获得的变量

    Method method = class_getInstanceMethod([self class], @selector(buyClothes));
    NSLog(@"name = %s",sel_getName(method_getName(method)));
     NSLog(@"TypeEncoding = %s",method_getTypeEncoding(method));
    NSLog(@"参数个数 = %u",method_getNumberOfArguments(method));
    IMP imp = method_getImplementation(method);
    

    输出

    2018-08-06 18:50:56.227579+0800 runtime[46116:1950929] name = buyClothes
    2018-08-06 18:50:56.227773+0800 runtime[46116:1950929] TypeEncoding = v16@0:8
    2018-08-06 18:50:56.227903+0800 runtime[46116:1950929] 参数个数 = 2
    

    相关文章

      网友评论

        本文标题:Runtime相关方法

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