The nature of the underlying principle class

Review the essence of IOS underlying principle object –(1), it can be seen that the instance object is actually a structure, so this structure is composed of class Pointers and member variables.

//Person @interface Person : NSObject { @public int _age; //4bytes int _level; //4bytes int _code; //4bytes } @end @implementation Person @endCopy the code

A Person object is a Person object compiled by xcrun-sdk iphoneOS clang-arch arm64-rewrite-objc main.m-o main64. CPP.

struct Person_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	int _age;
	int _level;
	int _code;
};
Copy the code

NSObject_IMPL structure:

struct NSObject_IMPL {
	Class isa;
};
Copy the code

So NSObject is included in memory

  • isaPointer to the
  • Other member variables

isa
instance
instance
isa

So what exactly does this ISA point to? Read on: Take a look at this code first:

NSObject *ob1=[[NSObject alloc]init];
NSObject *ob2=[[NSObject alloc]init];

Class cl1 = object_getClass([ob1 class]);
Class cl2 = object_getClass([ob2 class]);

Class cl3 = ob1.class;
Class cl4 = ob2.class;

Class cl5 = NSObject.class;

NSLog(@" %p %p %p %p %p",cl1,cl2,cl3,cl4,cl5);
//0x7fff8e3ba0f0 0x7fff8e3ba0f0 
//0x7fff8e3ba140 0x7fff8e3ba140 0x7fff8e3ba140
Copy the code

This code outputs the class of several NSObject objects and the address of the class object of NSObject, cl1==cl2, cl3==cl4==cl5.

The nature of the Class

We know that both a Class object and a metaclass object are of type Class, and the underlying Class and mete-class are Pointers to the objc_class structure, which is in memory.

Class objectClass = [NSObject class];        
Class objectMetaClass = object_getClass([NSObject class]);

Copy the code

Click on class to go inside and you can find it

typedef struct objc_class *Class;
Copy the code

A class object is actually a structure that points to an objc_class, so we can say that a class object or metaclass object is actually an objc_class structure in memory.

When you go inside objc_class, you often see this source code in the source code

struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILITY; //isa#if ! __OBJC2__Class _Nullable super_class // OBJC2_UNAVAILABLE; Const char * _Nonnull name //obj OBJC2_UNAVAILABLE; Long version // version OBJC2_UNAVAILABLE; long info //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; Struct objc_PROTOCOL_list * _Nullable protocols OBJC2_UNAVAILABLE;#endif

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

This code is clearly OBJC2_UNAVAILABLE, indicating that the code is no longer in use. So what is the internal structure of the objc_class structure? You can see inside objC_class by searching the runtime contents of objC

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() { 
        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); } //** is omittedCopy the code

We find that this structure inherits objc_Object and has some functions in it, because this is a C ++ structure, extended on C, so the structure can contain functions. Let’s go inside objc_Object and intercept some of the code

struct objc_object {
private:
    isa_t isa;

public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();

    // initIsa() should be used to init the isa of new objects only.
    // If this object already has an isa, use changeIsa() for correctness.
    // initInstanceIsa(): objects with no custom RR/AWZ
    // initClassIsa(): class objects
    // initProtocolIsa(): protocol objects
    // initIsa(): other objects
    void initIsa(Class cls /*nonpointer=false* /); void initClassIsa(Class cls /*nonpointer=maybe*/); void initProtocolIsa(Class cls /*nonpointer=maybe*/); void initInstanceIsa(Class cls, bool hasCxxDtor);Copy the code

So as we’ve seen before, the class stores the member variables of the class, the method list, the protocol list, intercepting the class_rw_t internal implementation code

struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint32_t version; const class_ro_t *ro; method_array_t methods; // Method list property_array_t properties; // Protocol_array_t protocols; // Protocol list Class firstSubclass; Class nextSiblingClass; ** / **Copy the code

Class_rw_t is obtained via bits.data(), which intercepts bits.data() to see the internal implementation, just bits&FAST_DATA_MASK.

    class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
Copy the code

Member variables are stored inside class_ro_T. Let’s look inside class_ro_T:

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endifconst uint8_t * ivarLayout; const char * name; method_list_t * baseMethodList; // List of methods protocol_list_t * baseProtocols; // protocol list const ivar_list_t * ivars; // List of member variables const uint8_t * weakIvarLayout; property_list_t *baseProperties; Method_list_t *baseMethods() const {returnbaseMethodList; }};Copy the code

Finally, I can sum up with a picture:

// // header. h // DAY02 - The nature of classes 1 // // Created by Charlie on 2019/7/2. // Copyright © 2019 www.fgyong.cn. All rights reserved. //#ifndef Header_h
#define Header_h

#import <Foundation/Foundation.h>
#import <objc/runtime.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; // The memory space occupied by the instance object#ifdef __LP64__
	uint32_t reserved;
#endifconst uint8_t * ivarLayout; const char * name; // Class name method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; // List of member variables 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; // method list property_list_t *properties; Const protocol_list_t * protocols; // Protocol list Class firstSubclass; Class nextSiblingClass; char *demangledName; };#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
	uintptr_t bits;
public:
	class_rw_t* data() {// provide the data() method for &fast_data_maskreturn(class_rw_t *)(bits & FAST_DATA_MASK); }}; Struct xx_objc_object {void *isa; }; Struct fy_objc_class: xx_objc_object {Class superclass; cache_t cache; class_data_bits_t bits; public: class_rw_t*data() {
		return bits.data();
	}
	
	fy_objc_class* metaClass() {// Provide the metaClass function to get the metaClass objectreturn(fy_objc_class *)((long long)isa & ISA_MASK); }};#endif /* Header_h */

Copy the code

H file import ‘main.m’, change main.m to main.mm or change some other.m to.mm run can run.

So let’s take the classic diagram and analyze the isa and superclass orientation next to each other

Instance object validation

P /x is used to print the hexadecimal address of obj. then the ISA pointer needs to go through an &isa_mask operation to get the real address. After implementation:

// Object Printing description of student: < student: 0x1021729C0 > (LLDB) p/x object->isa$0= 0x001dffff8e3ba141 NSObject (LLDB) p/x objectClassThe $1= 0x00007ffF8e3ba140 (LLDB) p/x 0x001Dffff8E3ba141&0x00007ffffffff8$2// Person Printing Description of person: = 0x00007ffF8e3ba140 <Person: 0x102175300> (lldb) p/x person->isa (Class)$3 = 0x001d800100002469 Person
(lldb) p/x 0x001d800100002469&0x00007ffffffffff8
(long) $4 = 0x0000000100002468
(lldb) p/x personClass
(fy_objc_class *) A $5= 0x0000000100002468// student (LLDB) p/x student->isa (Class)$6 = 0x001d8001000024b9 Student
(lldb) p/x 0x001d8001000024b9&0x00007ffffffffff8
(long) $7 = 0x00000001000024b8
(lldb) p/x studentClass
(fy_objc_class *) $8= 0 x00000001000024b8 / / studentclass and isa address 0 x00000001000024b8 (LLDB)Copy the code

From the above output, we can see that the INSTANCE object does store the ISA pointer and its member variables, and the address calculated after the & operation of the ISA pointer of the instance object is indeed the memory address of its corresponding class object. Thus we prove that ISA, superclass, points to lines 1, 2 and 3 in the graph.

Class object validation

Then we look at the class object, also through the last article, we know that the class object stores isa pointer, superclass pointer, as well as the class attribute information, class member variables information, class object methods, and class protocol information. We know that this information is stored in the class_rw_T of the class object, and we spy on it by casting it

//objectClass and objectMetaClass

(lldb) p/x objectClass->isa
(__NSAtom *) $6 = 0x001dffff8e3ba0f1
(lldb) p/x 0x001dffff8e3ba0f1&0x00007ffffffffff8
(long) $7 = 0x00007fff8e3ba0f0
(lldb) p/x objectMetaClass
(fy_objc_class *) $8 = 0x00007fff8e3ba0f0

//personClass and personMetaClass

(lldb) p/x personClass->isa
(__NSAtom *) $9 = 0x001d800100002441
(lldb) p/x personMetaClass
(fy_objc_class *) $10 = 0x0000000100002440
(lldb) p/x 0x001d800100002441&0x00007ffffffffff8
(long) $11 = 0x0000000100002440

//sutdentClass and studentMetaClass

(lldb) p/x studentClass->isa
(__NSAtom *) $12 = 0x001d800100002491
(lldb) p/x 0x001d800100002491&0x00007ffffffffff8
(long) $13 = 0x0000000100002490
(lldb) p/x studentMetaClass
(fy_objc_class *) $14 = 0x0000000100002490

Copy the code

There is the result of objectMetaClass = = objectClass – > isa = = 0 x00007fff8e3ba0f0, personClass – > isa = = personMetaClass = = 0 x0000000100002440, studen TClass – > isa = = studentMetaClass x0000000100002490 = = 0. Thus we prove that ISA, the superclass pointer in the diagram, points to lines 4, 5, and 6 of isa, and to lines 7,8, and 9 of superclass pointer.

Meta-class object validation

The meta-class contains the isa pointer, the superclass pointer, and the class method information of the class. We also know that meta-class metaclasses have the same structure as class metaclasses, but store different information, and that the ISA pointer of the metaclasses points to the base metaclasses, and the ISA pointer of the base metaclasses points to itself. A superclass pointer to a metaclass object points to a metaclass object of its parent class, and a superclass pointer to a metaclass object of its base class points to an object of its class. As with the class object, we mock the person metaclass by calling the.data function, which does &fast_data_mask (0x00007FFFFFFFF8ul) to bits and converts it to class_rw_t.

// objectMetaClass->superclass = 0x00007fff8e3ba140  NSObject
//objectMetaClass->isa =   0x00007fff8e3ba0f0
//objectMetaClass = 0x00007fff8e3ba0f0

(lldb) p/x objectMetaClass->superclass
(Class) $20 = 0x00007fff8e3ba140 NSObject
(lldb) p/x objectMetaClass->isa
(__NSAtom *) $21 = 0x001dffff8e3ba0f1
(lldb) p/x 0x001dffff8e3ba0f1&0x00007ffffffffff8
(long) $22 = 0x00007fff8e3ba0f0
(lldb) p/x objectMetaClass
(fy_objc_class *) $23 = 0x00007fff8e3ba0f0

// personMetaClass->superclas=0x00007fff8e3ba0f0
//personMetaClass->isa=0x00007fff8e3ba0f0
//personMetaClass = 0x0000000100002440

(lldb) p/x personMetaClass->superclass
(Class) $25 = 0x00007fff8e3ba0f0
(lldb) p/x personMetaClass->isa
(__NSAtom *) $26 = 0x001dffff8e3ba0f1
(lldb) p/x personMetaClass
(fy_objc_class *) $30= 0x0000000100002440 // studentMetaClass->superclas=0x0000000100002440 //studentMetaClass->isa=0x00007fff8e3ba0f0 (lldb)  p/x studentMetaClass->superclass (Class)$27 = 0x0000000100002440
(lldb) p/x studentMetaClass->isa
(__NSAtom *) $28 = 0x001dffff8e3ba0f1
(lldb) p/x 0x001dffff8e3ba0f1 & 0x00007ffffffffff8
(long) $29 = 0x00007fff8e3ba0f0
Copy the code

StudentMetaClass ->isa,personMetaClass->isa,objectMetaClass->isa ObjectMetaClass = p/x objectMetaClass = p/x StudentMetaClass – > superclass = 0 x0000000100002440, personMetaClass = 0 x0000000100002440 verification line 12, PersonMetaClass ->isa= 0x00007ffF8e3ba0f0 and objectMetaClass = 0x00007ffF8e3ba0f0 ObjectMetaClass ->superclass = 0x00007FFF8e3ba140 NSObject Validate line 10.

Conclusion:

Where does the object’s ISA point to?

  • The ISA of an instance object points to a class object
  • The ISA of a class object points to a meta-class object
  • The ISA of a meta-class object points to a meta-class object of the base class
  • Class and meta-class have the same memory structure, but the values are different

Where is the OC class information stored?

  • Object methods, properties, member variables, and protocol information are stored in class objects
  • Class methods are stored in meta-class objects
  • The value of the member variable is stored in the Instance object

Data download

  • Download of learning materials
  • demo code

The most afraid of a mediocre life, but also comfort their ordinary valuable.

This article is less pictures, I think or follow the code to knock again, more impressed.