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
} OBJC2_UNAVAILABLE;
/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar;
OBJC_EXPORT const char *ivar_getName(Ivar v)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT const char *ivar_getTypeEncoding(Ivar v)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT ptrdiff_t ivar_getOffset(Ivar v)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
Ivar应用
@interface FBAnimal : NSObject
{
int _age;
UIColor *_color;
}
@end
@implementation FBAnimal
@end
- (void)use_Ivar
{
Ivar age = class_getInstanceVariable([FBAnimal class], "_age");
Ivar color = class_getInstanceVariable([FBAnimal class], "_color");
NSLog(@"ivarName = %s, ivarType = %s, ivarOffset = %ld", ivar_getName(age), ivar_getTypeEncoding(age), ivar_getOffset(age));
NSLog(@"ivarName = %s, ivarType = %s, ivarOffset = %ld", ivar_getName(color), ivar_getTypeEncoding(color), ivar_getOffset(color));
}
output:
ivarName = _age, ivarType = i, ivarOffset = 8
ivarName = _color, ivarType = @"UIColor", ivarOffset = 16
Ivar总结
- ivar_name:数据成员name
- ivar_type:数据成员类型
- ivar_offset:数据成员相对于实例对象首地址offset
api
struct objc_ivar_list {
int ivar_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_ivar ivar_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
OBJC_EXPORT BOOL class_addIvar(Class cls, const char *name, size_t size,
uint8_t alignment, const char *types)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT size_t class_getInstanceSize(Class cls)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT Ivar class_getInstanceVariable(Class cls, const char *name)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT Ivar class_getClassVariable(Class cls, const char *name)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT const uint8_t *class_getIvarLayout(Class cls)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT void class_setIvarLayout(Class cls, const uint8_t *layout)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT const uint8_t *class_getWeakIvarLayout(Class cls)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
应用
@interface FBAnimal : NSObject
{
int _food1;
int _food2;
}
@end
@interface FBAnimal ()
{
int _food3;
int _food4;
}
@end
@interface FBAnimal ()
{
int _food5;
int _food6;
}
@end
@implementation FBAnimal
{
int _food7;
int _food8;
}
@end
@interface FBDog : FBAnimal
{
int _age;
int _color;
}
@end
@implementation FBDog
@end
- (void)class_ivars
{
NSLog(@"FBAnimal instance size = %lu", class_getInstanceSize([FBAnimal class]));
NSLog(@"FBDog instance size = %lu", class_getInstanceSize([FBDog class]));
NSLog(@"instance variable");
Ivar dogVar = class_getInstanceVariable([FBDog class], "_food1");
NSLog(@"ivarName = %s, ivarType = %s, ivarOffset = %ld", ivar_getName(dogVar), ivar_getTypeEncoding(dogVar), ivar_getOffset(dogVar));
NSLog(@"animal ivar list:");
unsigned int animalIvarCnt = 0;
Ivar* animalIvarList = class_copyIvarList([FBAnimal class], &animalIvarCnt);
for(int i = 0; i < animalIvarCnt; ++i)
{
Ivar thisIvar = animalIvarList[i];
NSLog(@"ivarName = %s, ivarType = %s, ivarOffset = %ld", ivar_getName(thisIvar), ivar_getTypeEncoding(thisIvar), ivar_getOffset(thisIvar));
}
free(animalIvarList);
NSLog(@"dog ivar list:");
unsigned int dogIvarCnt = 0;
Ivar* dogIvarList = class_copyIvarList([FBDog class], &dogIvarCnt);
for(int i = 0; i < dogIvarCnt; ++i)
{
Ivar thisIvar = dogIvarList[i];
NSLog(@"ivarName = %s, ivarType = %s, ivarOffset = %ld", ivar_getName(thisIvar), ivar_getTypeEncoding(thisIvar), ivar_getOffset(thisIvar));
}
free(dogIvarList);
}
output:
FBAnimal instance size = 40
FBDog instance size = 48
instance variable
ivarName = _food1, ivarType = i, ivarOffset = 8
animal ivar list:
ivarName = _food1, ivarType = i, ivarOffset = 8
ivarName = _food2, ivarType = i, ivarOffset = 12
ivarName = _food5, ivarType = i, ivarOffset = 16
ivarName = _food6, ivarType = i, ivarOffset = 20
ivarName = _food3, ivarType = i, ivarOffset = 24
ivarName = _food4, ivarType = i, ivarOffset = 28
ivarName = _food7, ivarType = i, ivarOffset = 32
ivarName = _food8, ivarType = i, ivarOffset = 36
dog ivar list:
ivarName = _age, ivarType = i, ivarOffset = 40
ivarName = _color, ivarType = i, ivarOffset = 44
总结
- class_addIvar不支持对已存在class object add,不支持对meta-class object add,只能对objc_allocateClassPair和objc_registerClassPair之间新创建class object add
- class_getInstanceSize同sizeof(c struct)考虑数据成员内存对齐
- class_getInstanceVariable(class object)和class_getClassVariable(meta-class object)包含super_class
- class_copyIvarList不包含super_class
- _food1 offset为8是因为FBAnimal从NSObject继承了Class isa(指针类型,字长为8,offset为0)
- 继承体系数据成员offset排列顺序:父类->子类
- 同一类数据成员offset排列顺序:primary class interface->extension interface->primary class implementation的隐式extension interface
- 同一类多个extension数据成员offset排列顺序:按extension interface定义顺序逆序排列,即先定义extension interface排后面,后定义extension interface排前面
- 同一interface(primary class interface,extension interface,primary class implementation的隐式extension interface)数据成员offset排列顺序:按数据成员定义顺序排列,即先定义数据成员排前面,后定义数据成员排后面