Previous article: OC Low-level (ISA, Class Objects, metaclass Objects)

Verify the isa

In our last blog, we introduced ISA, class objects, and metaclass objects. The relationship between them was introduced. Today we’re going to test it a little bit.

Create a simple and quick MacOC project, of course, iOS projects can also be. Is to define a Person class that inherits from NSObject. You don’t have to have any attributes, you just have this class. Next, define a Student class, which inherits from Person, and again doesn’t need to have any attributes, just this class. We use these two classes to create objects in main.m. The code is simple as follows:

And then we’re going to make a breakpoint on the NSLog line. Run the program. Let’s repeat the following three steps:

Step 1: x/4gx: Prints the contents of the object address stored in four bytes. The contents of the first byte are isa Pointers. Step 2: p/x: Prints the contents of the first byte in step 1 & the mask. Isa & mask. Step 3: Po the results obtained in step 2.

As we summarized in our previous article, the ISA pointer to the Person instance object points to the Person class object. Let’s start by printing x/4gx person (x/4gx, which prints the contents of memory in hexadecimal format. 4gx means reading 4 bytes, each byte in hexadecimal format). The first 8 bytes stored at the person address are isa, as shown below:

On the Mac, the mask is 0x00007ffffffffff8ULL. We get isa and the mask (which is the person object). We just p/x the result (printed in hexadecimal) and get a new address. This address is the address of the class object.And then Po the address, get the Person. The results are shown below

X /4gx is the address of the class to get its contents, and p/x is the first byte of the contents (isa of the class object) and the upper mask (equivalent to getting the metaclass object pointed to by the isa pointer). And then Po this address. The result is still a Person (but in this case a metaclass object). The results are shown below:

Repeat the above operations (x/4gx, the contents of the first byte of p/x & the mask, Po) and you get NSObject (equivalent to using isa and the upper mask of Person’s metaclass object to get the metaclass object of NSObject, which is printed out as NSObject), as shown below

So again, you still get NSObject (equivalent to using the ISA and the upper mask of the NSObject metaclass object, you get the object that the ISA of the NSObject metaclass object points to, again, is NSObject). The result is shown below.

Once again, you still get NSObject. And the contents stored in it are exactly the same (proving that the ISA of NSObject’s metaclass object points to itself).

Using student’s printing, the same process is not demonstrated here.

Verify the superclass

Class objects and metaclass objects have superClass Pointers to implement the inheritance relationship between class objects and metaclass objects. Again, the inheritance relationship only exists in class objects and metaclass objects. Instance objects have no inheritance relationship.

And here, let’s add the Class thing. In apple’s source code, we find the Class definition, which is derived from the objc_Object structure. The source code is as follows:

typedef struct objc_class *Class;
Copy the code
//objc_class is a structure inherited from objc_Object

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);
    }

    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...// There is a lot of code below, there is not a complete paste
// This code comes from objc-runtime-new.h on line 1244 in objC4-787.2.tar. gz
Copy the code

Objc_objcet has an ISA pointer, so objc_class (Class) has isa in the first byte. Next comes the superclass pointer, which is also of Class type. Let’s verify the superclass pointer. It’s the same thing we verified isa on the same project. Again, we read the memory contents of Person with x/4gx, p/x, and then find his class object with the first ISA and the upper mask. X /4gx this metaclass object. At this point, we read out the memory contents of the metaclass object. According to our summary, the second byte stores the information of the parent class, and we use the Po command, which prints the second byte as an object. You get NSObject. Verifies that Person inherits from NSObject. We are using the same process to validate student. You can find the Person/NSobject. To NSObject, the print superclass is going to be nil. It’s a perfect validation of that image. My own print is shown below.

If you validate metaclass objects, the same process is described above and will not be described here.