iOS 面试总结- 类的本质(一)

作者: Figo_OU | 来源:发表于2019-07-07 10:51 被阅读39次

    类的分类:

    实例对象(instance)
    类对象(class)
    元类对象(meta-class)

    问题:

    1.类信息是存放在什么地方的呢?

    实例对象:存放的具体对象的成员变量的值,
    类对象中存放着:类的属性,成员变量,对象方法信息,协议信息,isa,superclass
    元类对象中存放着:类方法信息,isa,superclass
    每个类在内存中有且只有一个class对象(类对象),有且只有一个元类对象

    [NSObject class]  //类对象的获取
    Class meteClass = object_getClass([NSObject class]); //元类对象获取
    

    2.一个NSObject对象占用多少内存?

    在系统alloc的时候,会分配16个字节。(通过malloc_size函数验证)
    但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数验证)
    当小于16个字节时,系统也会默认开辟16个字节的空间用于存放对象。

    3.每个对象中都有一个isa指针。这个指针的作用是什么呢?

    instance对象的isa指向class对象
    class对象的isa指向meta-class对象
    meta-class对象的isa指向基类的meta-class对象
    NSObject的元类isa指向自身、superclass指向NSObject的类对象。这样才能形成一个闭环。
    文字太枯燥,show me the code

    @interface JQApple : JQFruit
    @end
    
    @implementation JQApple
    - (instancetype)init{
        self = [super init];
        if (self) {
            NSLog(@"%@", NSStringFromClass([self class]));
            NSLog(@"%@", NSStringFromClass([super class]));
        }
        return self;
    }
    @end
    

    转自https://www.jianshu.com/p/b1274e3e3768,里面有详解。

    4.如何查看Class是否为meta-class
    BOOL result  = class_isMetaClass([NSObject class]);
    

    看到这里,我们大概已经了解了对象接收到消息时,oc中消息分发机制。

    5.那么有个疑问哈,既然对象的消息响应要走这么长一段流程,那么对象响应性能岂不是很慢吗?但实际上oc中的响应效率是很高的。系统这里面是做的什么操作呢?

    苹果底层用散列表缓存了方法,缓存过程中会通过方法名作为key,用指针地址&上一个mask(mask的值为散列表长度-1,这样保证了得出的索引值小于散列表的长度),从而求出索引值,根据索引值来存放方法实现。当想对象放松objc_send的时候,也是通过该方法获取索引值。这样通过一个位运算就可以获得方法的实现。

    附:
    消息分发机制过程:

    1.
    在Objective-C中,方法调用是一个消息发送的过程(在java,C++等静态语言中是函数调用)。
    OC对象发送一个消息的过程如下:
    1.向对象发送消息
    2.在缓存中查找是否有匹配方法。如果有则响应,否则继续
    3.在对象的类对象的方法列表中(method list)查找是否有匹配方法,如果有则响应,否则继续
    4.在对象的父类的缓存中查找是否有匹配方法。如果有则响应,否则继续
    5.在对象的父类的方法列表中(method list)查找是否有匹配方法。如果有则响应,否则继续
    6.进入动态解析 -(BOOL)resolveInstanceMethod:(SEL)sel;- (BOOL)resolveClassMethod:(SEL)sel;查看是否有动态添加方法实现。如果有则响应,否则继续
    7.进入消息重定向 -(id)forwardingTargetForSelector:(SEL)sel;如果有指定消息接收对象则响应,否则(指:返回nil或者self)继续
    8.进入方法签名- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector返回方法签名并进入下一步,否则调用doesNotRecongnizeSelector:方法并抛出异常。
    9.进入消息转发 - (void)forwardInvocation:(NSInvocation *)aInvocation;如果有指定消息转发对象则响应,否则调用doesNotRecongnizeSelector:方法并抛出异常。
    

    我们思考个问题:

    有person类和student类
    class Person{
        +(void)test{
            nslog(@"123");
        }
    }
    
    class Student : Person{
    }
    
    当用一个Student对象调用test方法时,打印会执行么?
    [[Student alloc] test];
    

    相关文章

      网友评论

        本文标题:iOS 面试总结- 类的本质(一)

        本文链接:https://www.haomeiwen.com/subject/issmhctx.html