之前章节
01Class的结构
02.消息机制
1.以下代码输出了什么?
@interface Person : NSObject
@end
@interface Student : Person
@end
@implementation Student
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"[self class] = %@", [self class]);
NSLog(@"[self superclass] = %@", [self superclass]);
NSLog(@"[super class] = %@", [super class]);
NSLog(@"[self superclass] = %@", [super superclass]);
}
return self;
}
@end
首先self不用说,1和2输出分别是Student和Person,至于3和4,主要考的其实是super的底层,super的底层源码我们使用clang编译为c++代码后如下:
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
/* super_class is the first class to search */
};
- receiver:消息接收者
- super_class:看注释很明白,就是找方法从父类方法开始找
那么我们的代码[super class]其实转过来就是大概如下
objc_msgSendSuper({self, Person}, @selector(class));
由于receiver是消息接收者,self对应着receiver,所以最终还是会对self发送class的消息,这时其实相当于[self class]和[self superclass],结果就是Student和Person,如下图
输出结果2.以下代码输出了什么?
BOOL res1 = [[Student new] isKindOfClass:[Person class]];
BOOL res2 = [[Student new] isMemberOfClass:[Person class]];
BOOL res3 = [[Person class] isMemberOfClass:[NSObject class]];
BOOL res4 = [[Person new] isMemberOfClass:[Person class]];
NSLog(@"%d %d %d %d ", res1, res2, res3, res4);
其实这个主要考察的是isKindOfClass和isMemberOfClass的区别了,这俩个方法分别是在NSObject实现的,而且是开源的,我们可以先看看它们的源码实现
+ (Class)superclass {
return self->getSuperclass();
}
- (Class)superclass {
return [self class]->getSuperclass();
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- isKindOfClass:比较多次,它首先和cls参数相比,然后继续跟父类相比,也就是会循环到父类去,跟继承有关系
- isMemberOfClass:比较一次,只跟传进来的cls对比
输出结果自然是:1 0 0 1
3.以下代码是否能运行成功,可以的话输出什么
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (void)print;
@end
@implementation Person
- (void)print
{
NSLog(@"name = %@", self.name);
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
id cls = [Person class];
void *obj = &cls;
[(__bridge id)obj print];
}
@end
这道题太蛋疼了,我也不太懂,要画图才能理清思绪
id cls = [Person class];
那么画出来的图如下:
cls内存分布结构模拟图接下来
void *obj = &cls;
obj内存分布结构模拟图
从图中可以看出,obj指向的是cls的地址,而cls的地址指向的是PersonClass的地址,而PersonClass的地址就是isa的地址(首地址)
最后print方法如下图:
简单来说,代码里有调用[super viewDidLoad],这里系统会创建一个变量self传入进去给到receiver,所以会分配一个栈空间内存,栈空间内存机制是从高位向地位开始分配器,所以self内存地址会大一些,如0x009这样,然后接下来到cls,这时会分配0x001这样子,当我调用name的属性的时候,isa是0x001,那么加多8个字节,就是0x009,也就是说name的地址值就是0x009,那0x009不就是self吗,所以结果会输入控制器值:name = ViewController: 0x....这样
网友评论