preface

Usually when you create an object, you inherit from NSObject to create a new class, so who does NSObject inherit from? Or what is the underlying principle of the class? Let’s explore this in detail.

This article explores the nature of the object

The preparatory work

  • Create a newProject

  • inmain.mAdds a class to theZLObject, type a breakpoint and execute.

Case analysis

1. Explore the underlying object
  • $p obj: Displays the address of an obj object.

  • $x/4gx OBj address: Displays the ISA and memory usage of the obj object.

  • $p/x ISA address & Mask Address: do and with the mask

  • $Po and operation address: View the association class

The process is as follows:

The mask is __86_64__ mask address 0x00007FFFFFFFF8ULL, and the final address of ZLObject is 0x0000000100008260

2. Keep exploring

With the address 0x0000000100008260 of ZLObject above, the isa and ISA_MASK operations are performed again. Finally, the address 0x0000000100008238 is still ZLObject.

Now that’s a little bit odd, why are they both ZLObject, but not in the same memory location?

Explore again

Again with the new ZLObject address of 0x0000000100008238, the isa and ISA_MASK calculations are performed again, and the final result is the address of 0x00007FFf92C9D0F0, which is NSObject.

There are two questions:

  • Is there a connection between ZLObject and ZLObject?

  • What does ISA for NSObject point to?

4. Method verification

Add the method shown below and print its memory.

The print result is as follows:

In this case, we can get the conclusion: The isa of the object is pointing to the class, that is, the memory address of ZLObject 0x0000000100008260, then what does the ISA of the class point to? Why this memory address is also a ZLObject.

5. MachO file analysis

For MachO file exploration, go to MachO File Analysis

Through the analysis of MachOView, directly define all symbols data under Symbol Table, search for class, and get:

  • To find the0x0000000100008260The memory address of, whose symbolic subscript is_OBJC_CLASS_$_ZLObject, that is,ZLObject.
  • To find the0x0000000100008238The memory address of, whose symbolic subscript is_OBJC_METACLASS_$_ZLObject, known as theZLObjectThe metaclass.

Conclusion a

  • Object points to the class

  • The ISA of the class points to the metaclass

  • Metaclasses are generated by the system compiler.

The essence of the MetaClass

The above analysis raises two questions, the first of which has been proven twice, that ZLObject is a class and a metaclass. So, what does ISA for NSObject point to? So let’s continue our exploration.

Nsobject. class memory address 0x00007FFF92C9d118 is different from the previous NSObject address 0x00007FFF92C9d0f0. So 0x00007FFf92C9d0f0 is the metaclass of NSObject.

So what does ISA for the NSObject metaclass point to?

By analysis, the ISA of the NSObject metaclass still points to the NSObject metaclass.

Conclusion two

  • Isa for a metaclass points to the root metaclass

  • Isa for the root metaclass still points to the root metaclass

  • For NSObject, it’s also the root class, and isa for the root class also points to the root metaclass

The essence of the SuperClass

ZLObject () and NSObject () point to isa (). What about SuperClass ()?

1. NSObject SuperClass

Create the following class and print its memory:

The print result is as follows:

Description:

  • The superclass of NSObject is nil

  • The metaclass of NSObject is still NSObject

2. ZLObject SuperClass

First look at the case where the superclass of a class is NSObject and print its metaclass:

The print result is as follows:

Note: The superclass of the ZLObject metaclass is the NSObject metaclass

3. ZLSubObject SuperClass

Create ZLObject subclass ZLSubObject and print the memory shown in the figure:

The printing situation is as follows:

Note: The superclass of ZLSubObject’s metaclass is ZLObject’s metaclass.

Conclusion three

  • NSObject’s superclass is nil, and its metaclass’s superclass is NSObject

  • Metaclasses of parent classes also have inheritance relationships.

The final result is two diagrams, one is the isa pointing diagram of the class, the other is the inheritance chain diagram of the class.

Memory migration

1. Common pointer

Print result:

Constant 10 is in the constant area and can be referenced by different Pointers. The reference principle is value copy.

2. Array pointer

Print result:

Description:

  • Using an array index to fetch an address has the same effect as using a pointer offset. How about &c[0] and b + 1 in the figure above

  • The first address of the array is the address of the first element of the array.

  • The size of the pointer offset is related to the size of the bytes used by the array elements, such as int in the figure above, so the printed address is off by 4, also known as the step size.

Class memory structure

The objc_class method is implemented as follows:

The memory structure is as follows:

Therefore, if you want to get bits, you must know the memory bytes of superclass and cache, and then use the memory offset to get the bits.

Since ISA is 8 bytes, it will not be described here.

1. superclass

Superclass is 8 bytes, just like isa, because it isa Class structure type

2. cache

The valid code for cache_t is as follows:

Neither the cache_t method nor the static declaration fields are in the structure body, so you can get the bits’ memory offset by simply analyzing the valid code above to get the size of the memory consumed by cache_t.

The size of the explicit_atomic

outside of the complex: explicit_atomic is a generic pointer, so its size is determined by < uintPtr_t >, which is 8 bytes. You can also use sizeof(uintptr_t) to see its size in bytes.

2. Size of the Consortium:

Description:

  • Mask_t is of type uint32_t, so it is 4 and uint16_t is of type 2.

  • is a pointer to a structure, so it is 8.

  • Union internal memory sharing, and mutually exclusive features, so the total size of 8.

conclusion

The cache usage is 16 bytes

The memory offset of bits is ISA + Superclass + Cache, and the total size is 32

Class

1. To obtainbitsData:

As shown in the figure above, the first address of the class is 0x1000081E8, so offset by 32 bytes from the first address of the class is bits.

At this point the bits’ data is stored in $4.

In the above analysis of the structure of objc_class, data() can be accessed.

$4->data() = “class_rw_t”;

2. To obtainclass_rw_tData:

So the class_rw_t data is available, but you don’t know where the required properties and methods are.

3. The analysisclass_rw_tStructure:

Properties () and methods() get the properties and methods of the class.

4. To obtainproperty_array_tlist

5. Getlistptr

6. Getproperty_list_tData:

7. Use C++ arraysget()Method to get the properties of a class:

8. Do the same for the classmethods()

The last step, get(0), does not get the data, so the fetching method is different from the property.

Analysis of 9.method_t

10. Callbig()Function.

Class to explore the underlying flowchart