iOS面试题

iOS面试-[self class] vs [super cla

2020-02-26  本文已影响0人  xxxxxxxx_123

TAnimalTCat两个类,如下代码,请问打印结果是什么?为什么?

@interface TAnimal : NSObject

@end

#import "TAnimal.h"

@implementation TAnimal

@end
@interface TCat : TAnimal

@end

#import "TCat.h"
#import <objc/message.h>

@implementation TCat

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

@end
#import <Foundation/Foundation.h>
#import "TAnimal.h"
#import "TCat.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TCat *c = [[TCat alloc] init];
    }
    return 0;
}

运行程序,控制台输出:

2020-02-19 11:31:56.116405+0800 LGTest[33763:1022523] ==[self class]==TCat
2020-02-19 11:31:56.117147+0800 LGTest[33763:1022523] ==[super class]==TCat

打印结果竟然都是TCat,这是为什么呢?
根据class方法的代码,可知:

- (Class)class {
    return object_getClass(self);
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

inline Class 
objc_object::getIsa() 
{
    if (!isTaggedPointer()) return ISA();
}

inline Class 
objc_object::ISA() 
{
    return (Class)(isa.bits & ISA_MASK);
}

从代码我们可以知道-class方法如果传入的实例对象,返回的则是类,由于self是当前类的实例对象,所以[self class]的结果是当前类,也就是TCat

那么[super class]的返回是什么呢?

汇编分析

打开汇编,进行分析,可以发现,[super class]其实调用的是objc_msgSendSuper

image

而其具体方法如下:

objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)

struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};

那么我们可以通过发送消息来进行分析:

struct objc_super cat_super = {
    self,
    class_getSuperclass([self class])
};
        
id ms = objc_msgSendSuper(&cat_super, @selector(class));
NSLog(@"===objc_msgSendSuper===%@===", ms);

运行程序,打印结果如下:


image

clang分析

使用clangTCat.m进行编译,我们可以得到以下结果:

clang -rewrite-objc TCat.m -o TCat.cpp
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
        
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("TCat"))}, sel_registerName("class"));

也可以得出,[self class]其实调用的是objc_msgSend,参数是selfsel_registerName("class");而[super class]调用的是objc_msgSendSuper,参数是
{(id)self, (id)class_getSuperclass(objc_getClass("TCat"))}sel_registerName("class")

总结:

上一篇 下一篇

猜你喜欢

热点阅读