Skip to content

类与对象

jiaxw32 edited this page Jun 6, 2020 · 4 revisions

isa 与 superclass

image

object

typedef struct objc_object *id;

/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

Class

before _OBJC2_

typedef struct objc_class *Class;

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list **methodLists;
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

_OBJC2_

  • objc_class

    typedef struct objc_class *Class;
    
    struct objc_class : objc_object {
        // 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_rw_t *data() const {
            return bits.data();
        }
        void setData(class_rw_t *newData) {
            bits.setData(newData);
        }
        ...
    }
    
  • class_data_bits_t

    class_data_bits_t is the class_t->data field (class_rw_t pointer plus flags). The extra bits are optimized for the retain/release and alloc/dealloc paths.

    struct class_data_bits_t {
      friend objc_class;
    
      // Values are the FAST_ flags above.
      uintptr_t bits;
    
      ...
    
      public:
    
      class_rw_t* data() const {
          return (class_rw_t *)(bits & FAST_DATA_MASK);
      }
      void setData(class_rw_t *newData)
      {
          ASSERT(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
          // Set during realization or construction only. No locking needed.
          // Use a store-release fence because there may be concurrent
          // readers of data and data's contents.
          uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
          atomic_thread_fence(memory_order_release);
          bits = newBits;
      }
    }
  • class_rw_t

    struct class_rw_t {
      // Be warned that Symbolication knows the layout of this structure.
      uint32_t flags;
      uint16_t version;
      uint16_t witness;
    
      const class_ro_t *ro;
    
      method_array_t methods;
      property_array_t properties;
      protocol_array_t protocols;
    
      Class firstSubclass;
      Class nextSiblingClass;
    
      char *demangledName;
    
      #if SUPPORT_INDEXED_ISA
          uint32_t index;
      #endif
  • class_ro_t

    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;
    #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;
    
        ...
    }
    

Property

typedef struct property_t *objc_property_t;

struct property_t {
    const char *name;
    const char *attributes;
};

/// Defines a property attribute
typedef struct {
    const char *name;           /**< The name of the attribute */
    const char *value;          /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;

struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};

Ivar

/// An opaque type that represents an instance variable.
typedef struct ivar_t *Ivar;

struct ivar_t {
#if __x86_64__
    // *offset was originally 64-bit on some x86_64 platforms.
    // We read and write only 32 bits of it.
    // Some metadata provides all 64 bits. This is harmless for unsigned 
    // little-endian values.
    // Some code uses all 64 bits. class_addIvar() over-allocates the 
    // offset for their benefit.
#endif
    int32_t *offset;
    const char *name;
    const char *type;
    // alignment is sometimes -1; use alignment() instead
    uint32_t alignment_raw;
    uint32_t size;
};


struct ivar_list_t : entsize_list_tt<ivar_t, ivar_list_t, 0> {
    bool containsIvar(Ivar ivar) const {
        return (ivar >= (Ivar)&*begin()  &&  ivar < (Ivar)&*end());
    }
};

Method

typedef struct method_t *Method;

struct method_t {
    SEL name;
    const char *types;
    MethodListIMP imp;
};

// Two bits of entsize are used for fixup markers.
struct method_list_t : entsize_list_tt<method_t, method_list_t, 0x3> {
    bool isUniqued() const;
    bool isFixedUp() const;
    void setFixedUp();

    uint32_t indexOfMethod(const method_t *meth) const {
        uint32_t i = 
            (uint32_t)(((uintptr_t)meth - (uintptr_t)this) / entsize());
        ASSERT(i < count);
        return i;
    }
};

SEL and IMP

/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

/// A pointer to the function of a method implementation. 
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
#endif

lldb 调试

  • Person 对象内存结构

    (lldb) po [personA _ivarDescription]
    <Person: 0x60000377d9e0>:
    in Person:
        _name (NSString*): nil
        _age (long): 0
    in NSObject:
        isa (Class): Person (isa, 0x10e8b36f0)

    Person 实例对象personAisa 指针指向 Person

  • Person 类内存结构

    (lldb) memory read --size 8 --format x --count 2 0x10e8b36f0
    0x10e8b36f0: 0x000000010e8b36c8(Person 类 isa,指向元类) 0x00007fff89be2d00 (Person 类父类,指向 NSObject)
  • Person 父类

    (lldb) p/x class_getSuperclass([person class])
    (Class) $120 = 0x00007fff89be2d00 NSObject

    0x00007fff89be2d00Person 父类 NSObject,与上面读取的地址相同

  • Person 元类,内存结构

    (lldb) memory read --size 8 --format x --count 2 0x000000010e8b36c8
    0x10e8b36c8: 0x00007fff89be2cd8(Person 元类 isa,指向 NSObject 元类) 0x00007fff89be2cd8(Person 元类父类,指向 NSObject 元类)

    Person 元类的 isasuper_class 都指向 NSObject 的元类 0x00007fff89be2cd8

  • NSObject 内存结构

    (lldb) memory read --size 8 --format x --count 2 0x00007fff89be2d00
    0x7fff89be2d00: 0x00007fff89be2cd8(NSObject isa 指向元类) 0x0000000000000000(NSOjbect 父类指向 nil)
  • NSObject 元类内存结构

    (lldb) memory read --size 8 --format x --count 2 0x00007fff89be2cd8
    0x7fff89be2cd8: 0x00007fff89be2cd8(NSObject 元类 isa 指向自身) 0x00007fff89be2d00(NSOjbect 元类的父类指向 NSObject 类)
Clone this wiki locally