preface

For iOSer, objects are all the time, maybe you don’t have objects, but you’re working with objects every day. So today we’re going to find out what our object really is.

First, the nature of the object

We use the alloc method to create an object. In my last article, I briefly explored the alloc process of exploring the portal. In this article, we learned that an object is a space bound to a class. What are the things inside the object? Let’s explore with some questions.

1, NSObject

We create any project, we write any project and we go into a system class, and we keep going in and eventually we find that they inherit from NSObject

As shown in the figure,NSObjectThere’s only one in thereisaIt seems like it’s gone at this point, but it can’t be gone that easy. We need a new approachClang

2, Clang

Clang: a C language family frontend for LLVM

The Clang project provides a language front-end and tooling infrastructure for languages in the C language family (C, C++, Objective C/C++, OpenCL, CUDA, and RenderScript) for the LLVM project. Both a GCC-compatible compiler driver (clang) and an MSVC-compatible compiler driver (clang-cl.exe) are provided.

Clang is a front-end to LLVM’s C language family. Clang provides LLVM with a language front end and tool infrastructure for the C language family (C, C++, target C/C++, OpenCL, CUDA, and RenderScript) languages. Both a GCC-compatible compiler driver (CLang) and an MSVC-compatible compiler driver (clang-cl.exe) are provided. (Don’t laugh, use tools to translate)

3. Use Clang to explore objects

Simply compile.m files into.cpp

    clang -rewrite-objc main.m -o main.cpp
Copy the code

We create a class LGPerson in the source file main.m as shown below:

Then run the compiled command on the terminal to get what is shown below.cppFile:

Open the file and search directlyLGPerson

You can findLGPersonIt inherits from the structureobjc_objectAnd weOCcreateLGPersonIt’s for the time beingNSObjectAnd get the structureobjc_objectisNSObjectThe underlying implementation of.

Taking a closer look at the screenshot, we can confirm that this is the declaration section by commenting on the next two lines, and we can see that the property testName that was declared before our declaration is not quite the same length, but it does not affect our judgment. What we declared before was a property, but here it becomes a member variable. Let’s go a little bit further down

Look, what I’ve circled is the realization duck. But what are these two methods on testName? Let’s declare another member variable, newTestName, as shown below:

Compile again and the result looks like this:

At a glance, nonewTestNameWe all know that member variables and attributes are the same, but the difference is that attributes are automatically generated when they are declaredgetandsetMethods. So the two methods here are automatic generationgetandset.

NSObject_IMPL {, NSObject_IMPL {, NSObject_IMPL {, NSObject_IMPL {, NSObject_IMPL {, NSObject_IMPL { Because we want to look inside the NSObject_IMPL, the result looks like this:

NSObject_IMPL has an ISA. Let’s look at the isa Class, as shown in the figure below:

Class is the structure pointer to objc_class.

4, summarize

Clang takes us through the contents of the object, so we can go back to objc’s source code. With Clang’s results, we can search directly for objc_object {objc_class, as shown in the figure below:

Second, the isa

In the above exploration, one of the key things we’ll find is isa, the structure pointer to objC_class, which we’ll need to explore next.

1, a domain

In the program, some information storage does not need a complete byte, only a few bits, to save storage space C language support “bit domain” structure. Specifically, a byte is divided into segments, each representing an object, so that a single byte can represent multiple variables. Bit-fields are essentially a type of structure.

First we create a structure whose member variables are placeholders for1As shown in figure:

Look at the size of it

Four bytes, but we’re only using one byte of space in time. Using bitfields, as shown:

Run the program again and promise the result:

Turned out to be1Is there a lot of room left? This is the bitfield.

2. Consortium

Union, also known as Commons, is a special data type that allows you to store different data types in the same memory location. You can define a union with multiple members, but only one member can have a value at any time. Federation provides an efficient way to use the same memory location.

Definition method: Use union definition.

To get an idea, let’s define a union, as shown in the figure below:

Then the breakpoint is assigned to view:

Execute program, breakpoint view:

As explained earlier, postassignment has an effect on the previously assigned variable. Look at the size:

8 bytes The size of a double.

3, the isa

Isa is the only variable that exists in NSObject. How do we check that? There will be ways to bind ISA while alloc is exploring, so let’s go inside.

In the initIsa method we can see that isa is of type ISA_t.

CLS = uintptr_t; bits = uintptr_t; unsigned long = 8; isa = 8; CLS and bits are mutually exclusive, and ISA_BITFIELD literally means bit field, as shown in the figure below:

Here are the arm64 and X86_642 architecture, we first look at the overall description of the X86_64 as a reference, one by one analysis as follows

uintptr_t nonpointer : 1; Indicates whether to enable pointer optimization for isa Pointers. 0: indicates pure ISA Pointers. 1: indicates not only the address of class objects, but also the class information and reference count of objects. uintptr_t has_assoc : 1; Associated object flag bit, 0 absent, 1 present. uintptr_t has_cxx_dtor : 1; Does the object have a destructor for C++ or Objc? If it has a destructor, it needs to do the destructor logic. If not, the object can be released more quickly. uintptr_t shiftcls : 44; Store the value of a class pointer. With pointer optimization enabled, 33 bits are used to store class Pointers in the ARM64 architecture and 44 bits are used to store class Pointers in the x86 architecture. uintptr_t magic : 6; Used by the debugger to determine whether the current object is a real object or has no space to initialize. uintptr_t weakly_referenced : 1; Weak variable that indicates whether an object is or has been referred to an ARC. Objects without weak references can be freed faster. uintptr_t deallocating : 1; Flags whether the object is freeing memory. uintptr_t has_sidetable_rc : 1; When the object reference technique is greater than 10, the variable is borrowed to store the carry. uintptr_t extra_rc : 8; Represents the reference count value of this object, which is actually the reference count value minus 1. For example, if the object's reference count is 10, extra_rc is 9. If the reference count is greater than 10, the following has_sideTABLE_rc is used.Copy the code

We graphically represent the bits:

To return to the place where the isa method is bound, newisa.shiftcls = (uintptr_t) CLS >> 3; Shiftcls stores the value of a class pointer. CLS is a class pointer. Moving 3 to the right gives shiftcls the positions of nonpointer, has_ASsoc, and has_cxx_dtor free and then avoids them. Run the program we breakpoint to view:

Enter a breakpoint and then set the breakpoint in the initIsa method:

If magic is 0, newisa has not been initialized. Next step:

newisathebitsThe assignment forISA_MAGIC_VALUEaftermagicIt’s got a value, it’s initialized, it’s inISA_BITFIELDTo see theISA_MAGIC_VALUEA value of0x001d800000000001Use a programming calculator to view:

At this time47to52The locationmagicHave a valueisaAlready initialized;0The locationnonpointerfor1According to theisaNot only the address of the class object, but also the class information, the reference count of the object, and so on. Moving on:

has_cxx_dtorAssign, continue:

shiftclsBound to theclsInitialization is done. Let’s go backperson:

isaIs the first pointer0x001d800100008225Since iOS is small end mode, we need to get itshiftclsI have to move to the right3Get rid of the first three and move it to the left20 (17 + 3)Take out the next 17 and move to the right17Reset, get toLGPerson: