美文网首页
ios的本质

ios的本质

作者: guoguojianshu | 来源:发表于2021-07-02 16:27 被阅读0次

    ios对象本质是转换为c++的结构体

    • 可以把main函数编译为c++的文件
    1. 跳转到mian函数的文件位置
    cd /Users/ruicong/Desktop/oc对象的本质/oc的本质/oc的本质/
    

    2.编译mian为c++文件

    clang -rewrite-objc main.m -o main.cpp
    

    如果报错

    报错的图片
    使用 xcrun命令,-sdk是指定平台的为iphoneos, -arch是指定架构为arm64,-rewrite-objc指定重新的文件为main.m文件,-o表示输出的文件地方
    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
    

    NSObject对象的本质是NSObject_IMPL结构体,这个结构体只有一个成员isa

    nsobject对象底层图

    一个NSObject对象占用的多少内存

    • 系统分配了16个字节给NSObject对象(通过malloc_size函数获取),但是NSObject对象内部只使用了8个字节的空间(arm64下,可以通过class_getInstanceSize函数获得)
    #import <malloc/malloc.h>
    #import <objc/runtime.h>
    
    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    #import <malloc/malloc.h>
    #import <objc/runtime.h>
    //nsobjcectimplementation
    struct NSObject_IMPL {
        Class isa;
    };
    
    int main(int argc, char * argv[]) {
        NSString * appDelegateClassName;
        @autoreleasepool {
            // Setup code that might create autoreleased objects goes here.
            appDelegateClassName = NSStringFromClass([AppDelegate class]);
          NSObject * objc =  [[NSObject alloc]init];
          NSInteger size =  malloc_size((__bridge void *)objc);
          NSInteger size1 =  class_getInstanceSize([NSObject class]);
        }
        NSLog(@"Hello Word");
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
    }
    
    • 在程序中打一个端点,获取到对象的地址,然后在xcode中Debug--debug Workflow--viewMemory中输入的对象的内存地址
      内存地址

    地址是16进制的,一位16进制数,用4位二进制数表示,两位就是8位进制数,8位二进制是一个字节,下面表示出来(红框)的是16个字节


    内存地址图片

    常用的LLDB指令

    • print,p :打印
    • po : 打印对象
    • 读取内存

    • memory read 读取内存,可以简写为x
    memory read 0x2827ac000
    
    x 0x2827ac000
    
    • 修改内存地址的值,memory write
      修改第九个字节为09,原来是00
    memory write 0x2827ac009 09
    

    从19开始为0,开始往后面数就是内存地址一个个的0x2827ac001,0x2827ac002,直到0x2827ac009

    0x2827ac000: 19 72 62 d8 a1 01 00 00 00 09 00 00 00 00 00 00 .rb.............

    • 带有格式的读取方式

    memory read/数量格式字节数 内存地址
    x/数量格式字节数 内存地址

    格式

    x是16进制,f是浮点,d是10进制
    字节大小
    b:byte 1字节,h:half word 2字节
    w:word 4字节,g:giant word 8字节

     x/4xg 0x2827ac000
    

    0x2827ac000: 0x000001a1d8627219 0x0000000000000900
    0x2827ac010: 0x0000000000000000 0x0000000000000000
    4个数量,16进制的格式,4个字节(是16进制格式,一个位16进制数是4位二进制数,2个16进制数,是8位二进制数,8位二进制是一个字节,两位16进制数占用一个字节)

    x/4xw 0x2827ac000
    

    0x2827ac000: 0xd8627219 0x000001a1 0x00000900 0x00000000

    高字节和低字节

    • 0x1234 其中12就是数据的高字节部分,34就是低字节部分

    cpu的大小端

    • 小端模式:
      低地址存放是数据的低字节数据,高地址存放的是字节数据的高字节
    • 大端模式:
      字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。 大小端分布图
      所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
      ios cpu都是小端模式
      内存地址
      这个是小端模式,存储的数据应该是这样的
      0x000001A1040F5649
      0x00000004
      0x00000005

    结构体内存对齐

    结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节
    oc对象的最小的内存大小是16个字节

    因为结构体里面有个isa指针,这个指针是8个字节的,所需要的内存大小,必须能够被8整除,所有最少得16个字节,不足的在后面用字节补齐

    实例对象,在内存中存储的是自己的成员变量

        NSObject * objc =  [[NSObject alloc]init];
    
            NSObject * objc1 =  [[NSObject alloc]init];
    

    这两个实例对象创建出来的实例对象的指针地址是不一样的

     NSLog(@"%p,%p",objc,objc1);
    

    2021-06-29 18:24:15.086998+0800 oc的本质[1263:580933] 0x280190100,0x280190110

    类对象,类对象在内存中只有一份

    Class classobjc =  objc_getClass([@"NSObject" UTF8String]);
            Class classobjc1 = [NSObject class];
            Class classobjc2 = [objc class];
            Class classobjc3 = object_getClass(objc);
            NSLog(@"%p,%p,%p,%p",classobjc,classobjc1,classobjc2,classobjc3);
    

    注意:object_getClass(objc);方法中,传入的是实例对象,获得才是类对象,如果里面传入的是类对象或者类,获得的是元类对象

    2021-06-29 20:29:12.227673+0800 oc的本质[1308:609002] 0x1f5fcb248,0x1f5fcb248,0x1f5fcb248,0x1f5fcb248

    元类对象,每个类只有一个元类对象

    • 将类对象或者类当做参数传入,获得元类对象
      Class objectMetaClass = object_getClass([NSObject class]);
          Class objectMetaClass1 = object_getClass(classobjc2);
    

    2021-06-29 20:37:03.850001+0800 oc的本质[1314:610924] 0x1f5fcb220,0x1f5fcb220

    类对象存储的信息

    class对象在内存中存储的信息主要包括
    isa指针
    superclass指针
    类的属性信息(@property)、类的对象方法信息(instance method)
    类的协议信息(protocol)、类的成员变量信息(ivar)
    这里的成员变量信息:不是存储的什么值,而是指的是成员变量的类型和成员变量名字是什么

    元类对象存储的信息

    meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括
    isa指针
    superclass指针
    类的类方法信息(class method)

    isa指针

    • instance(实例对象)的isa指向class(类对象)
      当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
    • class(类对象)的isa指向meta-class(元类对象)
      当调用类方法时,通过class的isa指针找到meta-class,最后找到类方法的实现进行调用

    superclass指针

    有一个Student类继承Person类,Person类继承NSObject

    • Student的instance对象要调用Student类的对象方法时,会先通过isa找到Student的类对象,然后找到对象方法进行调用
    • Student的instance对象调用Person的对象方法时,会先通过isa指针找到Student的类对象(class),然后通过Student的类对象的superclass找到Person的类对象,最后找到对象方法的实现进行调用

    isa、superclass总结

    • instance的isa指向class
    • class的isa指向meta-class
    • meta-class的isa指向基类的meta-class
    • class的superclass指向父类的class
    • 如果没有父类,superclass指针为nil
    • meta-class的superclass指向父类的meta-class
    • 基类的meta-class的superclass指向基类的class


      isa指针和superclass指针

    通过isa指针获取到类的地址

    p/x就是以16进制形式进行打印

    • 要想通过实例对象的isa指针,存储的地址就是类对象的地址,就得在isa指针上&上一个ISA_MASK的偏移量 isa_mask
     JGPerson * person1 = [[JGPerson alloc]init];
     Class personClass1 =  [JGPerson class];
    
    • 获取person1的isa指针的地址
     p/x person1->isa
    (Class) $0 = 0x000021a10283d9a9 JGPerson
    
    • 获取类对象的地址
     p/x personClass1
    (Class) $1 = 0x000000010283d9a8 JGPerson
    
    • isa指针地址&上isa_mask的偏移量
    p/x 0x000021a10283d9a9 & 0x0000000ffffffff8ULL
    (unsigned long long) $2 = 0x000000010283d9a8
    

    isa_mask偏移量去掉ULL也可以的

     p/x 0x000021a10283d9a9 & 0x0000000ffffffff8
    (long) $3 = 0x000000010283d9a8
    

    类对象的isa指针,指向元类对象

    • 直接用类对象直接取里面的isa指针,会报错
    p/x personClass1->isa
    error: <user expression 4>:1:13: member reference base type 'Class' is not a structure or union
    personClass1->isa
    ~~~~~~~~~~~~^ ~~~
    
    • 可以自己写个结构体,与系统的样式一样的
    struct JG_objc_class{
        Class isa;
    };
    
    • 然后用类对象赋值这个给个结构体对象
     Class personClass1 =  [JGPerson class];
            struct JG_objc_class * personClass3 = (__bridge struct JG_objc_class *)(personClass1);
    
    • 获取metaclass对象
     Class personClass2 =  [JGPerson class];
      Class personMetaClass = object_getClass(personClass2);
    
    • 获取结构体中isa指针
    p/x personClass3->isa
    (Class) $0 = 0x0000000100dad980
    
    • 获取metaclass的指针
    p/x personMetaClass
    (Class) $1 = 0x0000000100dad980
    
    • 类对象的isa指针&上isa_mask的偏移量
     p/x 0x0000000100dad980 & 0x0000000ffffffff8ULL
    (unsigned long long) $3 = 0x0000000100dad980
    

    superclass指向父类

    struct JG_objc_class{
        Class isa;
        Class  super_class;
    };
    
            struct JG_objc_class * student3 =   (__bridge struct JG_objc_class *)([JGStudent class]);
    
         Class personClass1 =  [JGPerson class];
    
    
    p/x student3->super_class
    (Class) $0 = 0x00000001028c59a8 JGPerson
    
     p/x personClass1
    (Class) $2 = 0x00000001028c59a8 JGPerson
    

    可以验证student的类对象的super_class指针,指向的是JGPerson的类对象的地址

    验证类对象(class对象)和元类对象(meta对象)里面存放的信息

    • 要想验证类的信息,从源码中可以看到包含的信息
    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    
    } OBJC2_UNAVAILABLE;
    /* Use `Class` instead of `struct objc_class *` */
    

    但是这些信息在OBJC2.0就不起作用了,无效了,那只能从objc4-818.2这个源码进行查找,

    struct objc_class : objc_object {
      objc_class(const objc_class&) = delete;
      objc_class(objc_class&&) = delete;
      void operator=(const objc_class&) = delete;
      void operator=(objc_class&&) = delete;
        // Class ISA;
        Class superclass;
        cache_t cache;             // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    
        Class getSuperclass() const {
    #if __has_feature(ptrauth_calls)
    #   if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
            if (superclass == Nil)
                return Nil;
    
    #if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
            void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
            if ((void *)superclass == stripped) {
                void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
                if ((void *)superclass != resigned)
                    return Nil;
            }
    #endif
                
            void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
            return (Class)result;
    
    #   else
            return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
    #   endif
    #else
            return superclass;
    #endif
        }
    
        void setSuperclass(Class newSuperclass) {
    #if ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL
            superclass = (Class)ptrauth_sign_unauthenticated((void *)newSuperclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
    #else
            superclass = newSuperclass;
    #endif
        }
    
        class_rw_t *data() const {
            return bits.data();
        }
        void setData(class_rw_t *newData) {
            bits.setData(newData);
        }
    
        void setInfo(uint32_t set) {
            ASSERT(isFuture()  ||  isRealized());
            data()->setFlags(set);
        }
    
        void clearInfo(uint32_t clear) {
            ASSERT(isFuture()  ||  isRealized());
            data()->clearFlags(clear);
        }
    
        // set and clear must not overlap
        void changeInfo(uint32_t set, uint32_t clear) {
            ASSERT(isFuture()  ||  isRealized());
            ASSERT((set & clear) == 0);
            data()->changeFlags(set, clear);
        }
    
    #if FAST_HAS_DEFAULT_RR
        bool hasCustomRR() const {
            return !bits.getBit(FAST_HAS_DEFAULT_RR);
        }
        void setHasDefaultRR() {
            bits.setBits(FAST_HAS_DEFAULT_RR);
        }
        void setHasCustomRR() {
            bits.clearBits(FAST_HAS_DEFAULT_RR);
        }
    #else
        bool hasCustomRR() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
        }
        void setHasDefaultRR() {
            bits.data()->setFlags(RW_HAS_DEFAULT_RR);
        }
        void setHasCustomRR() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
        }
    #endif
    
    #if FAST_CACHE_HAS_DEFAULT_AWZ
        bool hasCustomAWZ() const {
            return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
        void setHasDefaultAWZ() {
            cache.setBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
        void setHasCustomAWZ() {
            cache.clearBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
    #else
        bool hasCustomAWZ() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_AWZ);
        }
        void setHasDefaultAWZ() {
            bits.data()->setFlags(RW_HAS_DEFAULT_AWZ);
        }
        void setHasCustomAWZ() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_AWZ);
        }
    #endif
    
    #if FAST_CACHE_HAS_DEFAULT_CORE
        bool hasCustomCore() const {
            return !cache.getBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
        void setHasDefaultCore() {
            return cache.setBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
        void setHasCustomCore() {
            return cache.clearBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
    #else
        bool hasCustomCore() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_CORE);
        }
        void setHasDefaultCore() {
            bits.data()->setFlags(RW_HAS_DEFAULT_CORE);
        }
        void setHasCustomCore() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_CORE);
        }
    #endif
    
    #if FAST_CACHE_HAS_CXX_CTOR
        bool hasCxxCtor() {
            ASSERT(isRealized());
            return cache.getBit(FAST_CACHE_HAS_CXX_CTOR);
        }
        void setHasCxxCtor() {
            cache.setBit(FAST_CACHE_HAS_CXX_CTOR);
        }
    #else
        bool hasCxxCtor() {
            ASSERT(isRealized());
            return bits.data()->flags & RW_HAS_CXX_CTOR;
        }
        void setHasCxxCtor() {
            bits.data()->setFlags(RW_HAS_CXX_CTOR);
        }
    #endif
    
    #if FAST_CACHE_HAS_CXX_DTOR
        bool hasCxxDtor() {
            ASSERT(isRealized());
            return cache.getBit(FAST_CACHE_HAS_CXX_DTOR);
        }
        void setHasCxxDtor() {
            cache.setBit(FAST_CACHE_HAS_CXX_DTOR);
        }
    #else
        bool hasCxxDtor() {
            ASSERT(isRealized());
            return bits.data()->flags & RW_HAS_CXX_DTOR;
        }
        void setHasCxxDtor() {
            bits.data()->setFlags(RW_HAS_CXX_DTOR);
        }
    #endif
    
    #if FAST_CACHE_REQUIRES_RAW_ISA
        bool instancesRequireRawIsa() {
            return cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);
        }
        void setInstancesRequireRawIsa() {
            cache.setBit(FAST_CACHE_REQUIRES_RAW_ISA);
        }
    #elif SUPPORT_NONPOINTER_ISA
        bool instancesRequireRawIsa() {
            return bits.data()->flags & RW_REQUIRES_RAW_ISA;
        }
        void setInstancesRequireRawIsa() {
            bits.data()->setFlags(RW_REQUIRES_RAW_ISA);
        }
    #else
        bool instancesRequireRawIsa() {
            return true;
        }
        void setInstancesRequireRawIsa() {
            // nothing
        }
    #endif
        void setInstancesRequireRawIsaRecursively(bool inherited = false);
        void printInstancesRequireRawIsa(bool inherited);
    
    #if CONFIG_USE_PREOPT_CACHES
        bool allowsPreoptCaches() const {
            return !(bits.data()->flags & RW_NOPREOPT_CACHE);
        }
        bool allowsPreoptInlinedSels() const {
            return !(bits.data()->flags & RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptCaches() {
            bits.data()->setFlags(RW_NOPREOPT_CACHE | RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptInlinedSels() {
            bits.data()->setFlags(RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptCachesRecursively(const char *why);
        void setDisallowPreoptInlinedSelsRecursively(const char *why);
    #else
        bool allowsPreoptCaches() const { return false; }
        bool allowsPreoptInlinedSels() const { return false; }
        void setDisallowPreoptCaches() { }
        void setDisallowPreoptInlinedSels() { }
        void setDisallowPreoptCachesRecursively(const char *why) { }
        void setDisallowPreoptInlinedSelsRecursively(const char *why) { }
    #endif
    
        bool canAllocNonpointer() {
            ASSERT(!isFuture());
            return !instancesRequireRawIsa();
        }
    
        bool isSwiftStable() {
            return bits.isSwiftStable();
        }
    
        bool isSwiftLegacy() {
            return bits.isSwiftLegacy();
        }
    
        bool isAnySwift() {
            return bits.isAnySwift();
        }
    
        bool isSwiftStable_ButAllowLegacyForNow() {
            return bits.isSwiftStable_ButAllowLegacyForNow();
        }
    
        uint32_t swiftClassFlags() {
            return *(uint32_t *)(&bits + 1);
        }
      
        bool usesSwiftRefcounting() {
            if (!isSwiftStable()) return false;
            return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
        }
    
        bool canCallSwiftRR() {
            // !hasCustomCore() is being used as a proxy for isInitialized(). All
            // classes with Swift refcounting are !hasCustomCore() (unless there are
            // category or swizzling shenanigans), but that bit is not set until a
            // class is initialized. Checking isInitialized requires an extra
            // indirection that we want to avoid on RR fast paths.
            //
            // In the unlikely event that someone causes a class with Swift
            // refcounting to be hasCustomCore(), we'll fall back to sending -retain
            // or -release, which is still correct.
            return !hasCustomCore() && usesSwiftRefcounting();
        }
    
        bool isStubClass() const {
            uintptr_t isa = (uintptr_t)isaBits();
            return 1 <= isa && isa < 16;
        }
    
        // Swift stable ABI built for old deployment targets looks weird.
        // The is-legacy bit is set for compatibility with old libobjc.
        // We are on a "new" deployment target so we need to rewrite that bit.
        // These stable-with-legacy-bit classes are distinguished from real
        // legacy classes using another bit in the Swift data
        // (ClassFlags::IsSwiftPreStableABI)
    
        bool isUnfixedBackwardDeployingStableSwift() {
            // Only classes marked as Swift legacy need apply.
            if (!bits.isSwiftLegacy()) return false;
    
            // Check the true legacy vs stable distinguisher.
            // The low bit of Swift's ClassFlags is SET for true legacy
            // and UNSET for stable pretending to be legacy.
            bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
            return !isActuallySwiftLegacy;
        }
    
        void fixupBackwardDeployingStableSwift() {
            if (isUnfixedBackwardDeployingStableSwift()) {
                // Class really is stable Swift, pretending to be pre-stable.
                // Fix its lie.
                bits.setIsSwiftStable();
            }
        }
    
        _objc_swiftMetadataInitializer swiftMetadataInitializer() {
            return bits.swiftMetadataInitializer();
        }
    
        // Return YES if the class's ivars are managed by ARC, 
        // or the class is MRC but has ARC-style weak ivars.
        bool hasAutomaticIvars() {
            return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
        }
    
        // Return YES if the class's ivars are managed by ARC.
        bool isARC() {
            return data()->ro()->flags & RO_IS_ARC;
        }
    
    
        bool forbidsAssociatedObjects() {
            return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
        }
    
    #if SUPPORT_NONPOINTER_ISA
        // Tracked in non-pointer isas; not tracked otherwise
    #else
        bool instancesHaveAssociatedObjects() {
            // this may be an unrealized future class in the CF-bridged case
            ASSERT(isFuture()  ||  isRealized());
            return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
        }
    
        void setInstancesHaveAssociatedObjects() {
            // this may be an unrealized future class in the CF-bridged case
            ASSERT(isFuture()  ||  isRealized());
            setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
        }
    #endif
    
        bool shouldGrowCache() {
            return true;
        }
    
        void setShouldGrowCache(bool) {
            // fixme good or bad for memory use?
        }
    
        bool isInitializing() {
            return getMeta()->data()->flags & RW_INITIALIZING;
        }
    
        void setInitializing() {
            ASSERT(!isMetaClass());
            ISA()->setInfo(RW_INITIALIZING);
        }
    
        bool isInitialized() {
            return getMeta()->data()->flags & RW_INITIALIZED;
        }
    
        void setInitialized();
    
        bool isLoadable() {
            ASSERT(isRealized());
            return true;  // any class registered for +load is definitely loadable
        }
    
        IMP getLoadMethod();
    
        // Locking: To prevent concurrent realization, hold runtimeLock.
        bool isRealized() const {
            return !isStubClass() && (data()->flags & RW_REALIZED);
        }
    
        // Returns true if this is an unrealized future class.
        // Locking: To prevent concurrent realization, hold runtimeLock.
        bool isFuture() const {
            if (isStubClass())
                return false;
            return data()->flags & RW_FUTURE;
        }
    
        bool isMetaClass() const {
            ASSERT_THIS_NOT_NULL;
            ASSERT(isRealized());
    #if FAST_CACHE_META
            return cache.getBit(FAST_CACHE_META);
    #else
            return data()->flags & RW_META;
    #endif
        }
    
        // Like isMetaClass, but also valid on un-realized classes
        bool isMetaClassMaybeUnrealized() {
            static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
            static_assert(RO_META == RW_META, "flags alias");
            if (isStubClass())
                return false;
            return data()->flags & RW_META;
        }
    
        // NOT identical to this->ISA when this is a metaclass
        Class getMeta() {
            if (isMetaClassMaybeUnrealized()) return (Class)this;
            else return this->ISA();
        }
    
        bool isRootClass() {
            return getSuperclass() == nil;
        }
        bool isRootMetaclass() {
            return ISA() == (Class)this;
        }
      
        // If this class does not have a name already, we can ask Swift to construct one for us.
        const char *installMangledNameForLazilyNamedClass();
    
        // Get the class's mangled name, or NULL if the class has a lazy
        // name that hasn't been created yet.
        const char *nonlazyMangledName() const {
            return bits.safe_ro()->getName();
        }
    
        const char *mangledName() { 
            // fixme can't assert locks here
            ASSERT_THIS_NOT_NULL;
    
            const char *result = nonlazyMangledName();
    
            if (!result) {
                // This class lazily instantiates its name. Emplace and
                // return it.
                result = installMangledNameForLazilyNamedClass();
            }
    
            return result;
        }
        
        const char *demangledName(bool needsLock);
        const char *nameForLogging();
    
        // May be unaligned depending on class's ivars.
        uint32_t unalignedInstanceStart() const {
            ASSERT(isRealized());
            return data()->ro()->instanceStart;
        }
    
        // Class's instance start rounded up to a pointer-size boundary.
        // This is used for ARC layout bitmaps.
        uint32_t alignedInstanceStart() const {
            return word_align(unalignedInstanceStart());
        }
    
        // May be unaligned depending on class's ivars.
        uint32_t unalignedInstanceSize() const {
            ASSERT(isRealized());
            return data()->ro()->instanceSize;
        }
    
        // Class's ivar size rounded up to a pointer-size boundary.
        uint32_t alignedInstanceSize() const {
            return word_align(unalignedInstanceSize());
        }
    
        inline size_t instanceSize(size_t extraBytes) const {
            if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
                return cache.fastInstanceSize(extraBytes);
            }
    
            size_t size = alignedInstanceSize() + extraBytes;
            // CF requires all objects be at least 16 bytes.
            if (size < 16) size = 16;
            return size;
        }
    
        void setInstanceSize(uint32_t newSize) {
            ASSERT(isRealized());
            ASSERT(data()->flags & RW_REALIZING);
            auto ro = data()->ro();
            if (newSize != ro->instanceSize) {
                ASSERT(data()->flags & RW_COPIED_RO);
                *const_cast<uint32_t *>(&ro->instanceSize) = newSize;
            }
            cache.setFastInstanceSize(newSize);
        }
    
        void chooseClassArrayIndex();
    
        void setClassArrayIndex(unsigned Idx) {
            bits.setClassArrayIndex(Idx);
        }
    
        unsigned classArrayIndex() {
            return bits.classArrayIndex();
        }
    };
    
    • 按照系统方法,大神提取出一个文件
    //
    //  MJClassInfo.h
    //  TestClass
    //
    //  Created by MJ Lee on 2018/3/8.
    //  Copyright © 2018年 MJ Lee. All rights reserved.
    //
    
    #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 */
    
    
    
    • 在main函数中引入这个文件,然后可以调用了
      在运行的时候,xcode会报错,因为.m格式的文件,只能编译occ的文件,这个文件是c++的,修改main.m文件为main.mm文件
    • 获取class的信息
            struct mj_objc_class  * studentClass4 = (__bridge struct mj_objc_class *)[JGStudent class];
    
    

    这个c++的结构体,可以向类一样的访问,可以去掉struct

             mj_objc_class  * studentClass5 = (__bridge  mj_objc_class *)[JGStudent class];
    
    
    • 获取类对象的信息
    class_rw_t * studentClassData = studentClass5 ->data();
    
    • 获取元类对象的信息
            class_rw_t * studentMetaClassData = studentClass5->metaClass()->data();
    
    
    • 打印结果为


      打印结果

    相关文章

      网友评论

          本文标题:ios的本质

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