美文网首页
isa、superclass的细节

isa、superclass的细节

作者: SKY_Tang | 来源:发表于2018-09-11 18:38 被阅读0次

    看下isa存值的问题

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    
    @interface MJPerson : NSObject <NSCopying>
    
    @end
    
    @implementation MJPerson
    
    - (id)copyWithZone:(NSZone *)zone
    {
        return self;
    }
    
    @end
    
    @interface MJStudent : MJPerson <NSCoding>
    
    @end
    
    @implementation MJStudent
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        
    }
    
    - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        return nil;
    }
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            MJPerson *person = [[MJStudent alloc] init];
            
            Class personClass = [MJPerson class];
            
            Class personMetaClass = object_getClass(personClass);
            
            NSLog(@"%p-----%p------%p", person, personClass, personMetaClass);
        }
        return 0;
    }
    

    断点打印

    断点打印

    打印得到personisa的指向的值为0x001d8001000012f1,打印的personClass地址为0x00000001000012f0

    好像不符合instance对象的isa指向class对象,这是因为从64bit开始,isa需要进行一次位运算,才能计算出真实地址,可以从objc4的源码找到

    ISA_MASK

    找到ISA_MASKX86_64(模拟器)下值是0x00007ffffffffff8

    ISA_MASK

    通过personisa0x00007ffffffffff8与运算得到0x00000001000012f0,和personClass打印的地址一致。

    superclass的存值是否有这个问题

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    
    @interface MJPerson : NSObject <NSCopying>
    
    @end
    
    @implementation MJPerson
    
    - (id)copyWithZone:(NSZone *)zone
    {
        return self;
    }
    
    @end
    
    @interface MJStudent : MJPerson <NSCoding>
    
    @end
    
    @implementation MJStudent
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        
    }
    
    - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        return nil;
    }
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            MJPerson *person = [[MJPerson alloc] init];
            
            MJStudent *student = [[MJStudent alloc] init];
            
            Class personClass = [MJPerson class];
            
            Class studentClass = [MJStudent class];
            
            Class personMetaClass = object_getClass(personClass);
            
            Class studentMetaClass = object_getClass(studentClass);
            
            NSLog(@"%p-----%p------%p", person, personClass, personMetaClass);
        }
        return 0;
    }
    

    断点打印

    superclass打印

    直接不能打印studentClasssuperclass指针,我们看看class类的结构

    objc4源码 objc源码

    自定义一个结构体mj_objc_class,强制转换class

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    
    @interface MJPerson : NSObject <NSCopying>
    
    @end
    
    @implementation MJPerson
    
    - (id)copyWithZone:(NSZone *)zone
    {
        return self;
    }
    
    @end
    
    @interface MJStudent : MJPerson <NSCoding>
    
    @end
    
    @implementation MJStudent
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        
    }
    
    - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        return nil;
    }
    
    @end
    
    struct mj_objc_class {
        Class isa;
        Class superclass;
    };
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            MJPerson *person = [[MJPerson alloc] init];
            
            MJStudent *student = [[MJStudent alloc] init];
            
            struct mj_objc_class *personClass = (__bridge struct mj_objc_class *)([MJPerson class]);
            
            struct mj_objc_class *studentClass = (__bridge struct mj_objc_class *)([MJStudent class]);
            
            struct mj_objc_class *personMetaClass = (__bridge struct mj_objc_class *)(object_getClass([MJPerson class]));
            
            struct mj_objc_class *studentMetaClass = (__bridge struct mj_objc_class *)(object_getClass([MJStudent class]));
            
            NSLog(@"%p-----%p------%p", person, personClass, personMetaClass);
        }
        return 0;
    }
    

    断点打印

    断点打印

    打印结果studentClasssuperclass的值0x00000001000012f8正好是personClass的地址,studentMetaClasssuperclass的值0x00000001000012d0正好是personMetaClass的地址,也就是superclass的值就是父类的地址

    现在研究class的结构

    class objc_class class_rw_t class_ro_t

    objc_class结构体存放的信息如图

    objc_class存放信息

    根据这个结构体写一个自己的类来强制转换class

    #import <Foundation/Foundation.h>
    
    #ifndef MJClassInfo_h
    #define MJClassInfo_h
    
    # if __arm64__
    #   define ISA_MASK        0x0000000ffffffff8ULL
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    # endif
    
    #if __LP64__
    typedef uint32_t mask_t;
    #else
    typedef uint16_t mask_t;
    #endif
    typedef uintptr_t cache_key_t;
    
    struct bucket_t {
        cache_key_t _key;
        IMP _imp;
    };
    
    struct cache_t {
        bucket_t *_buckets;
        mask_t _mask;
        mask_t _occupied;
    };
    
    struct entsize_list_tt {
        uint32_t entsizeAndFlags;
        uint32_t count;
    };
    
    struct method_t {
        SEL name;
        const char *types;
        IMP imp;
    };
    
    struct method_list_t : entsize_list_tt {
        method_t first;
    };
    
    struct ivar_t {
        int32_t *offset;
        const char *name;
        const char *type;
        uint32_t alignment_raw;
        uint32_t size;
    };
    
    struct ivar_list_t : entsize_list_tt {
        ivar_t first;
    };
    
    struct property_t {
        const char *name;
        const char *attributes;
    };
    
    struct property_list_t : entsize_list_tt {
        property_t first;
    };
    
    struct chained_property_list {
        chained_property_list *next;
        uint32_t count;
        property_t list[0];
    };
    
    typedef uintptr_t protocol_ref_t;
    struct protocol_list_t {
        uintptr_t count;
        protocol_ref_t list[0];
    };
    
    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;  // instance对象占用的内存空间
    #ifdef __LP64__
        uint32_t reserved;
    #endif
        const uint8_t * ivarLayout;
        const char * name;  // 类名
        method_list_t * baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars;  // 成员变量列表
        const uint8_t * weakIvarLayout;
        property_list_t *baseProperties;
    };
    
    struct class_rw_t {
        uint32_t flags;
        uint32_t version;
        const class_ro_t *ro;
        method_list_t * methods;    // 方法列表
        property_list_t *properties;    // 属性列表
        const protocol_list_t * protocols;  // 协议列表
        Class firstSubclass;
        Class nextSiblingClass;
        char *demangledName;
    };
    
    #define FAST_DATA_MASK          0x00007ffffffffff8UL
    struct class_data_bits_t {
        uintptr_t bits;
    public:
        class_rw_t* data() {
            return (class_rw_t *)(bits & FAST_DATA_MASK);
        }
    };
    
    /* OC对象 */
    struct mj_objc_object {
        void *isa;
    };
    
    /* 类对象 */
    struct mj_objc_class : mj_objc_object {
        Class superclass;
        cache_t cache;
        class_data_bits_t bits;
    public:
        class_rw_t* data() {
            return bits.data();
        }
        
        mj_objc_class* metaClass() {
            return (mj_objc_class *)((long long)isa & ISA_MASK);
        }
    };
    
    #endif /* MJClassInfo_h */
    

    因为有 C++混编,main.m改成main.mm

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    #import "MJClassInfo.h"
    
    // MJPerson
    @interface MJPerson : NSObject <NSCopying>
    {
    @public
        int _age;
    }
    @property (nonatomic, assign) int no;
    - (void)personInstanceMethod;
    + (void)personClassMethod;
    @end
    
    @implementation MJPerson
    
    - (void)test
    {
        
    }
    
    - (void)personInstanceMethod
    {
        
    }
    + (void)personClassMethod
    {
        
    }
    - (id)copyWithZone:(NSZone *)zone
    {
        return nil;
    }
    @end
    
    // MJStudent
    @interface MJStudent : MJPerson <NSCoding>
    {
    @public
        int _weight;
    }
    @property (nonatomic, assign) int height;
    - (void)studentInstanceMethod;
    + (void)studentClassMethod;
    @end
    
    @implementation MJStudent
    - (void)test
    {
        
    }
    - (void)studentInstanceMethod
    {
        
    }
    + (void)studentClassMethod
    {
        
    }
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        return nil;
    }
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        
    }
    @end
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            MJStudent *stu = [[MJStudent alloc] init];
            stu->_weight = 10;
            
            mj_objc_class *studentClass = (__bridge mj_objc_class *)([MJStudent class]);
            mj_objc_class *personClass = (__bridge mj_objc_class *)([MJPerson class]);
            
            class_rw_t *studentClassData = studentClass->data();
            class_rw_t *personClassData = personClass->data();
            
            class_rw_t *studentMetaClassData = studentClass->metaClass()->data();
            class_rw_t *personMetaClassData = personClass->metaClass()->data();
    
            NSLog(@"1111");
        }
        return 0;
    }
    

    断点打印

    superclass

    打印看到class对象studentClasssuperclassMJPersonclass对象,personClasssuperclassNSObjectclass对象。

    studentClassData personClass

    打印看到对象方法和属性信息都是存放在class对象中

    studentMetaClassData personMetaClassData

    打印看到类方法存放在meta-class对象中

    面试题

    对象的isa指针指向哪里?

    • instance对象的isa指向class对象
    • class对象的isa指向meta-class对象
    • meta-class对象的isa指向基类的meta-class对象

    OC的类信息存放在哪里?

    • 对象方法、属性、成员变量、协议信息,存放在class对象中
    • 类方法,存放在meta-class对象中
    • 成员变量的具体值,存放在instance对象

    相关文章

      网友评论

          本文标题:isa、superclass的细节

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