类继承体系
@interface FBAnimal : NSObject
{
int _food1;
int _food2;
}
- (void)dataOffset;
@end
@interface FBAnimal ()
{
int _food3;
int _food4;
}
@end
@interface FBAnimal ()
{
int _food5;
int _food6;
}
@end
@implementation FBAnimal
{
int _food7;
int _food8;
}
- (void)dataOffset
{
NSLog(@"_food1 offset = %ld", (char*)&_food1 - (char*)self);
NSLog(@"_food2 offset = %ld", (char*)&_food2 - (char*)self);
NSLog(@"_food3 offset = %ld", (char*)&_food3 - (char*)self);
NSLog(@"_food4 offset = %ld", (char*)&_food4 - (char*)self);
NSLog(@"_food5 offset = %ld", (char*)&_food5 - (char*)self);
NSLog(@"_food6 offset = %ld", (char*)&_food6 - (char*)self);
NSLog(@"_food7 offset = %ld", (char*)&_food7 - (char*)self);
NSLog(@"_food8 offset = %ld", (char*)&_food8 - (char*)self);
}
@end
@interface FBDog : FBAnimal
{
int _age;
int _color;
}
- (void)dataOffset;
@end
@implementation FBDog
- (void)dataOffset
{
[super dataOffset];
NSLog(@"_age offset = %ld", (char*)&_age - (char*)self);
NSLog(@"_color offset = %ld", (char*)&_color - (char*)self);
}
@end
- (void)dataOffset
{
FBAnimal *animal = [[FBAnimal alloc] init];
FBDog *dog = [[FBDog alloc] init];
NSLog(@"-----animal data offset-----");
[animal dataOffset];
NSLog(@"-----dog data offset-----");
[dog dataOffset];
}
output:
-----animal data offset-----
_food1 offset = 8
_food2 offset = 12
_food3 offset = 24
_food4 offset = 28
_food5 offset = 16
_food6 offset = 20
_food7 offset = 32
_food8 offset = 36
-----dog data offset-----
_food1 offset = 8
_food2 offset = 12
_food3 offset = 24
_food4 offset = 28
_food5 offset = 16
_food6 offset = 20
_food7 offset = 32
_food8 offset = 36
_age offset = 40
_color offset = 44
子类继承父类,不改变父类数据成员布局(数据成员相对于实例对象首地址offset),子类新增数据成员添加在父类末尾,类继承体系的这种内存布局确保了父类指针能正确访问父类数据成员对应内存空间,且不会访问到子类新增数据成员内存空间,因此把子类实例对象指针赋值给父类实例对象指针是安全的
结论:
- NSObject是oc类root,因此任何直接或间接继承自NSObject的oc类实例对象指针都可隐式转换为NSObject实例对象指针
- (void)class_convert
{
NSObject *object = [[NSObject alloc] init];
FBAnimal *animal = [[FBAnimal alloc] init];
FBDog *dog = [[FBDog alloc] init];
object = animal;
object = dog;
animal = dog;
}
id
id是objc_object指针类型,而NSObject本质是对objc_object的封装,因为把NSObject实例对象指针赋值给id类型是安全的,因为任何直接或间接继承自NSObject的oc类实例对象指针都可隐式转换为NSObject实例对象指针,因此自然也可隐式转换为id类型
- (void)id_convert
{
NSObject *object = [[NSObject alloc] init];
FBAnimal *animal = [[FBAnimal alloc] init];
FBDog *dog = [[FBDog alloc] init];
id anyobj;
anyobj = object;
anyobj = animal;
anyobj = dog;
}
Class
objc_object只有一个数据成员Class isa,相对于objc_object对象首地址offset为0,objc_class有若干数据成员,但其第一个数据成员为Class isa,相对于objc_class对象首地址offset为0,因此objc_object和objc_class在内存布局上满足父类和子类的关系,id是objc_object指针类型,Class是objc_class指针类型,因此Class类型可隐式转换为id类型
- (void)class_convert
{
Class anycls;
anycls = [NSObject class];
anycls = [FBAnimal class];
anycls = [FBDog class];
}
protocol
使用protocol类型两种方式:
- 类<protocol1, protocol2...> *对象名
- id<protocol1, protocol2...> 对象名
protocol无自定义数据成员,因此protocol类型本质上是id类型,只不过protocol纯粹作为接口使用,相较于id类型,protocol类型增加了编译期接口调用检查功能
结论:
- protocol类型作为特殊id类型,自然可隐式转换为id类型,protocol类型包含接口是id类型(无接口)包含接口超集
- 遵守protocol的oc类实例对象指针可隐式转换为protocol类型,类实例对象指针包含接口是protocol类型包含接口超集
- 若protocol类型A遵守的所有protocol亦被protocol类型B遵守,则B可隐式转换为A,因为B包含接口是A包含接口超集
@protocol FBFeedFood1
- (void)feedRice:(int)rice andMeat:(int)meat;
@end
@protocol FBFeedFood2
- (void)feedFruit:(int)fruit andFish:(int)fish;
@end
@protocol FBFeedFood <FBFeedFood1, FBFeedFood2>
@end
@protocol FBGuard
@required
- (void)watch;
@optional
- (void)attack;
@end
@interface FBAnimal : NSObject <FBFeedFood>
{
@public
int _food;
}
@end
@implementation FBAnimal
- (void)feedRice:(int)rice andMeat:(int)meat
{
NSLog(@"feedRice:andMeat:");
}
- (void)feedFruit:(int)fruit andFish:(int)fish
{
NSLog(@"feedFruit:andFish:");
}
@end
@interface FBDog : FBAnimal <FBGuard>
{
@public
int _vol;
}
- (void)bark;
@end
@implementation FBDog
- (void)bark
{
NSLog(@"bark");
}
- (void)watch
{
NSLog(@"watch");
}
@end
- (void)protocol_convert
{
FBAnimal* animal = [[FBAnimal alloc] init];
FBDog* dog = [[FBDog alloc] init];
id anyobj;
id<FBFeedFood1> feed1;
id<FBFeedFood2> feed2;
id<FBFeedFood> feed;
id<FBGuard> guard;
anyobj = feed1;
feed1 = animal;
feed1 = dog;
feed2 = animal;
feed2 = dog;
feed = animal;
feed = dog;
feed1 = feed;
feed2 = feed;
//feed1 = feed2;
//guard = animal;
guard = dog;
}
泛型id
id表示未知类类型,类型是确定的,只是不知道,即无法在编译期确定确切类型,运行期才能确定确切类型,因此id类型经常被容器用来作为泛型类型,作为一切类类型(包括instance object和class object)的root,因此一切类类型(包括instance object和class object)都可隐式转换为id类型,但这种转换是不安全的,需要开发者确定是否安全
- (void)id_convert
{
id anyobj;
NSObject *object;
FBAnimal *animal;
FBDog *dog;
id<FBFeedFood> feed;
id<FBGuard> guard;
object = anyobj;
animal = anyobj;
dog = anyobj;
feed = anyobj;
guard = anyobj;
}