iOS底层原理 - 探寻Runtime本质(四)

2018-07-24  本文已影响12人  hazydream

面试题引发的思考:

Q: 以下代码的打印内容是什么?

// TODO: -----------------  Person类  -----------------
@interface Person : NSObject
@end

@implementation Person
@end

// TODO: -----------------  Student类  -----------------
@interface Student : Person
@end

@implementation Student
- (instancetype)init
{
    self = [super init];
    if (self) {
        NSLog(@"[self class] = %@", [self class]);
        NSLog(@"[self superclass] = %@", [self superclass]);
        NSLog(@"---------------------------");
        NSLog(@"[super class] = %@", [super class]);
        NSLog(@"[super superclass] = %@", [super superclass]);
    }
    return self;
}
@end

// TODO: -----------------  main  -----------------
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [[Student alloc] init];
    }
    return 0;
}

打印结果应该是:

[self class] = Student
[self superclass] = Person
---------------------------
[super class] = Person
[super superclass] = NSObject

真实打印结果是:

真实打印结果

Q:为什么打印结果和想象中有出入?

面试题一

1> selfsuper

// TODO: -----------------  Person类  -----------------
@interface Person : NSObject
- (void)run;
@end

@implementation Person
- (void)run {
    NSLog(@"%s", __func__);
}
@end

// TODO: -----------------  Student类  -----------------
@interface Student : Person
@end

@implementation Student
- (void)run {
    [super run];
    NSLog(@"Student - run");
}
@end

通过xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.mStudent.m转化为C++代码查看其底层实现:

OC代码转化为C++

[super run];语句转化为C++代码:

((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){
(id)self, 
(id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));

// 简化代码
objc_msgSendSuper((__rw_objc_super){
        self,
        class_getSuperclass(objc_getClass("Student"))
    }, @selector(run));

// 继续简化代码
struct __rw_objc_super arg = {
        self,
        class_getSuperclass(objc_getClass("Student"))
    };
objc_msgSendSuper(arg, @selector(run));

由以上代码可知:

OC源码中搜索objc_msgSendSuper

objc_msgSendSuper函数

由OC源码可知:
objc_msgSendSuper函数传入的第一个参数为objc_super结构体;
objc_super结构体传入两个参数:
receiver消息接收者为self;
superclass决定从哪一个类开始查找方法的实现。

self、super调用方法流程

由上图可知:
super调用方法:消息接收者仍然是子类对象self,从父类开始查找方法的实现。

2> classsuperclass

classsuperclass的底层实现如下图所示:

class与superclass的底层实现

class方法的内部实现是根据消息接收者返回其对应的类对象。而class方法是在基类NSObject类中实现的。

[self class];[super class];的消息接收者都是本类Student
区别为:[self class];从本类类对象开始查找方法,[super class];从父类类对象开始查找方法。

superclass方法的内部实现是根据消息接收者返回其对应的父类的类对象。

[self superclass];[super superclass];的消息接收者都是父类Person
区别为:[self superclass];从父类类对象开始查找方法,[super superclass];从父类的父类类对象开始查找方法。

2. 面试题二

isa、superclass指向图

根据isasuperclass指向图,得到以下结论:

isMemberOfClass与isKindOfClass的底层实现

由以上源码可知:
结论一:isMemberOfClass判断左边类型 是否等于 右边类型;
结论二:isKindOfClass判断左边类型 是否等于 右边类型或其子类;
结论三:左边(实例对象) 对应 右边(类对象);
结论四:左边(类对象) 对应 右边(元类对象);
结论五:基类的元类的superclass指向基类。

// TODO: -----------------  Person类  -----------------
@interface Person : NSObject
@end

@implementation Person
@end

// TODO: -----------------  main  -----------------
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Person *person = [[Person alloc] init];
        NSLog(@"%d", [person isMemberOfClass:[Person class]]); // 1,结论一、三
        NSLog(@"%d", [person isMemberOfClass:[NSObject class]]); // 0,结论一、三
        NSLog(@"%d", [person isKindOfClass:[Person class]]);  // 1,结论二、三
        NSLog(@"%d", [person isKindOfClass:[NSObject class]]);  // 1,结论二、三

        NSLog(@"%d", [[Person class] isMemberOfClass:[NSObject class]]); // 0,结论一、四
        NSLog(@"%d", [[NSObject class] isMemberOfClass:[NSObject class]]); // 0,结论一、四
        NSLog(@"%d", [[Person class] isKindOfClass:[NSObject class]]); // 1,结论二、四、五
        NSLog(@"%d", [[NSObject class] isKindOfClass:[NSObject class]]); // 1,结论二、四、五
    }
    return 0;
}

3. 面试题三

// TODO: -----------------  Person类  -----------------
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (void)print;
@end

@implementation Person
- (void)print {
    NSLog(@"my name is %@", self.name);
}
@end

// TODO: -----------------  ViewController类  -----------------
QQ20190222-152850@2x.png QQ20190222-153008@2x.png

super的本质、栈空间、消息机制、访问成员变量的本质

上一篇 下一篇

猜你喜欢

热点阅读