每个人的学习方式不同,我习惯于先了解每个方法的使用方式是什么,方法是做什么用的。今天的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
是不是想起了一张图
- (了解)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) // 关联对象的内存管理语义
- 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
网友评论