数据成员
类只有instance object数据成员,没有class object数据成员,因此数据成员存储在class object(非meta-class object)的ivars中
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;
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;
/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
分析:
- 数据成员结构为objc_ivar,objc_ivar保存着数据成员名(ivar_name),数据成员类型(ivar_type,即数据成员字长),数据成员相对于instance object首地址offset(ivar_offset)和数据成员内存对齐(space),数据成员名唯一确定数据成员
- ivars是class object的数据成员list,因此同一class object中,数据成员名不能重名,否则编译器不能确定使用哪个数据成员,二义性错误,或者list中优先search到的数据成员名屏蔽list中之后重名数据成员(ignore之后重名数据成员),oc在编译期避免此情况发生
@interface FBAnimal : NSObject
{
@public
int _food1;
}
@end
@interface FBAnimal ()
{
@public
int _food2;
}
@end
@implementation FBAnimal
{
@public
int _food3;
}
@end
注:_food1,_food2,_food3不能重名
继承体系的数据成员
理论上子类数据成员和父类数据成员相互独立,互不影响,因为数据成员分处于不同的class object中,但在实际中,还是有所限制
@interface FBAnimal : NSObject
{
@public
int _food1;
}
@end
@interface FBAnimal ()
{
@public
int _food2;
}
@end
@implementation FBAnimal
{
@public
int _food3;
}
@end
@interface FBFood : NSObject
@end
@implementation FBFood
@end
primary class interface
@interface FBDog : FBAnimal
{
@public
//FBFood *_food1;
//FBFood *_food2;
//FBFood *_food3;
}
@end
@interface FBDog ()
@end
@implementation FBDog
@end
void member_access()
{
FBFood *food = [[FBFood alloc] init];
FBAnimal *animal1 = [[FBAnimal alloc] init];
FBAnimal *animal2 = [[FBDog alloc] init];
FBDog *dog = [[FBDog alloc] init];
animal1->_food1 = 5;
animal1->_food2 = 5;
animal1->_food3 = 5;
animal2->_food1 = 5;
animal2->_food2 = 5;
animal2->_food3 = 5;
dog->_food1 = 5;
dog->_food2 = 5;
dog->_food3 = 5;
}
注:FBDog的_food1,_food2,_food3与FBAnimal的_food1,_food2,_food3重名,编译error
extension
@interface FBDog : FBAnimal
@end
@interface FBDog ()
{
@public
FBFood *_food1;
FBFood *_food2;
FBFood *_food3;
}
@end
@implementation FBDog
@end
void member_access()
{
FBFood *food = [[FBFood alloc] init];
FBAnimal *animal1 = [[FBAnimal alloc] init];
FBAnimal *animal2 = [[FBDog alloc] init];
FBDog *dog = [[FBDog alloc] init];
animal1->_food1 = 5;
animal1->_food2 = 5;
animal1->_food3 = 5;
animal2->_food1 = 5;
animal2->_food2 = 5;
animal2->_food3 = 5;
dog->_food1 = food;
dog->_food2 = food;
dog->_food3 = food;
}
primary class implementation
@interface FBDog : FBAnimal
@end
@interface FBDog ()
@end
@implementation FBDog
{
@public
FBFood *_food1;
FBFood *_food2;
FBFood *_food3;
}
@end
void member_access()
{
FBFood *food = [[FBFood alloc] init];
FBAnimal *animal1 = [[FBAnimal alloc] init];
FBAnimal *animal2 = [[FBDog alloc] init];
FBDog *dog = [[FBDog alloc] init];
animal1->_food1 = 5;
animal1->_food2 = 5;
animal1->_food3 = 5;
animal2->_food1 = 5;
animal2->_food2 = 5;
animal2->_food3 = 5;
dog->_food1 = food;
dog->_food2 = food;
dog->_food3 = food;
}
总结
- 数据成员编译期bind,根据instance object指针类型确定数据成员search起始class object
- 从类体系结构分析,子类数据成员和父类数据成员可重名,但实际中primary class interface中数据成员不能与父类(直接或间接父类)数据成员重名,oc做此限制纯粹从类设计角度考虑,因为作为类提供者,一般只把primary class interface部分open给使用者,而隐藏extension和primary class implementation部分,子类继承父类(直接或间接父类),同理也一般只把primary class interface部分open给使用者,而隐藏extension和primary class implementation部分,这样一来,如果oc不做上述限制,作为子类使用者,就无法使用父类(直接或间接父类)primary class interface中open给使用者的与子类primary class interface部分同名数据成员了,因为被子类屏蔽了
isa
- NSObject包含Class isa数据成员,根据同一class object中,数据成员名不能重名,因此NSObject不允许再自定义isa数据成员
- Class isa定义在NSObject的primary class的interface中,因此继承自NSObject的子类(直接或间接子类)primary class interface中不能定义isa数据成员,extension和primary class implementation中则允许定义isa数据成员