Runtime相关方法

每个人的学习方式不同,我习惯于先了解每个方法的使用方式是什么,方法是做什么用的。今天的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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容