在OC中,成员变量就是一个结构体,如下:
struct objc_ivar{
char * ivar_name;
char *ivar_type;
int ivar_offset;
}
这个结构体描述了成员变量的名字,类型和偏移量。
同时runtime也为我们提供了相应的函数来获取类的成员变量的信息。
Ivar _Nonnull * _Nullable
class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount) ;//获取成员变量列表
const char * _Nullable
ivar_getName(Ivar _Nonnull v); //获取成员变量名
const char * _Nullable
ivar_getTypeEncoding(Ivar _Nonnull v); //获取成员变量类型
ptrdiff_t
ivar_getOffset(Ivar _Nonnull v); //获取成员变量偏移量
接下来,我们举个例子来演示一下如何用runtime获取成员变量的相关信息。
首先,我们定义一个Person类,这个类有三个成员变量。
@interface Person : NSObject
{
NSString * _name;
}
@property(nonatomic,assign) NSInteger age;
@property(nonatomic,strong) NSDictionary * dict;
@end
然后,我们获取该类,并打印出该类成员变量的信息。
#import <Foundation/Foundation.h>
#import "Person.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class p = [Person class];
NSLog(@"Person Class address: %p", p);
unsigned int outCount = 0;
//获取整个成员变量的列表,同时outCount变量可以获取成员变量列表中成员的个数
Ivar *ivars = class_copyIvarList(p, &outCount);
for(unsigned int i = 0;i<outCount;i++){ //获取每个成员变量的信息
Ivar ivar = ivars[i];
const char *ivar_name = ivar_getName(ivar);
const char *ivar_type = ivar_getTypeEncoding(ivar);
ptrdiff_t diff = ivar_getOffset(ivar);
NSLog(@"ivar_name : %s, ivar_type : %s, diff : %td.",ivar_name,ivar_type,diff);
}
free(ivars);
}
return 0;
}
打印结果如下:
2021-03-16 23:17:07.489178+0800 Project3[43237:4167326] Person Class address: 0x100008230
2021-03-16 23:17:07.489533+0800 Project3[43237:4167326] ivar_name : _name, ivar_type : @"NSString", diff : 8.
2021-03-16 23:17:07.489571+0800 Project3[43237:4167326] ivar_name : _age, ivar_type : q, diff : 16.
2021-03-16 23:17:07.489591+0800 Project3[43237:4167326] ivar_name : _dict, ivar_type : @"NSDictionary", diff : 24.
Program ended with exit code: 0
从结果中我们可以看到,类Person的基地址为0x100008230,并且每个成员相对于基地址有8个字节的偏移。并且每个成员变量都有ivar_name、ivar_type、ivar_offset属性。从而可以证明:成员变量就是一个结构体!