Summary of basic principles of iOS

The main purpose of this article is to analyze the structure of class & class. The whole article is a series of explorations around a class

The analysis of the class

Class analysis is mainly to analyze the trend of ISA and inheritance relationship

The preparatory work

Define two classes

  • Inherited fromNSObjectThe class ofLGPerson.

  • Inherited fromLGPersonThe class ofLGTeacher

  • Define two objects in main:person & teacher

The metaclass

First, let’s introduce metaclasses through LLDB debugging in a case

  • Add a breakpoint in the LGTeacher section of main and run the program
  • Enable LLDB debugging. The following figure shows the debugging process

According to the debugging process, we have a question: Why p/ X 0x001D800100008365&0x00007FFFFFFFFFF8ULL and P /x 0x0000000100008338&0x00007FFFFFFFFff8ull in the figure Class information is printed out as LGPerson, right?

  • 0x001D800100008365 is the ISA pointer address of the Person object, and the ampersand results in the creation of the Person class LGPerson

  • 0x00000001000022B0 is the isa pointer address of the class indicated by the class information obtained in ISA, that is, the ISA pointer address of the class of LGPerson. In Apple, we refer to the class of LGPerson as metaclass

  • So, the root reason why both prints are lgPersons is because of metaclasses

Description of metaclasses

To explain what metaclass is, there are mainly the following points:

  • We all know thatobjecttheisaIs pointing toclass.classIn fact, is also aobject, can be calledClass object, itsisaThe bitfield points to apple definedThe metaclass
  • The metaclassissystemTo itdefineandcreateAre made ofThe compilerDone, and in the process,classtheattributionFrom theThe metaclass
  • The metaclass 是Class object 的class, eachclassThere’s always a unique oneThe metaclassUsed to storeInformation about class methods.
  • The metaclassItself isnameless, withclassphaseassociated, so usedA name of the same kind

The next step is to explore the direction of the metaclass, or isa, using the LLDB command, as shown in the figure below, to get a chain of relationships: object –> class –> metaclass –> NSobject, which points to itself

conclusion

As you can see from the picture

  • object 的 isaPoint to theclassAlso calledClass object)
  • class 的 isaPoint to theThe metaclass
  • The metaclass 的 isaPoint to theA metaclass, i.e.,NSObject
  • A metaclass 的 isaPointing to itoneself

How many nsobjects are there?

And as you can see, the last root metaclass is NSObject, is this NSObject the same NSObject that we know about in our day development?

There are two authentication modes

  • [Method 1]lldbCommand to verify
  • 【 Method 2 】codevalidation

[Method 1] LLDB command verification

We also use LLDB debugging to verify that the two NSObjects are the same, as shown in the figure below

You can see that the metaclass of the last NSObject class is also NSObject, the same metaclass of the root NSObject in LGPerson above, so you can conclude that there is only one copy of the root metaclass NSObject in memory, and the metaclass of the root metaclass is pointing to itself

[Method 2] Code verification

Get classes in three different ways to see if they print the same address

As you can see from the results, the printed addresses are all the same, so there is only one copy of NSObject, that is, there is only one copy of NSObject in memory

[Interview question] : How many classes are there?

Since there is only one copy of a class’s information in memory, there is only one copy of a class object

The famous ISA bit-inheritance diagram

Based on the above exploration and various validations, the relationship between object, class, metaclass, and root metaclass is shown below

Isa walk a

There are several explanations of where ISA is heading:

  • Instance of SubclasstheisaPoint to theClass (class)
  • Class object (class) isaPoint to theMeta Classes
  • Meta ClassestheisaPoint to theRoot Metal class
  • Root Metal class 的isaPointing to itoneselfIn itself, formThe closed loopHere,A metaclassisNSObject

Superclass walk a

There are also several explanations for the direction of superclasses (i.e. inheritance relationships) :

  • Inheritance relationships between classes:

    • Class (ttf_subclass)Inherited fromsuperClass
    • superClassInherited fromRootClass, where the root class refers toNSObject
    • The root classInherited fromnil, soThe root classnamelyNSObjectCan be understood asOrigin of all things, that is, out of thin air
  • Metaclasses also have inheritance. The inheritance relationship between metaclasses is as follows:

    • SubClass metaclass (Metal SubClass)Inherited fromSuperClass (metal SuperClass)
    • SuperClass (metal SuperClass)Inherited fromRoot metal Class
    • Root Metal ClassInheritance inRoot class, where the root class refers toNSObject
  • [Note] There is no inheritance relationship between instance objects, but there is inheritance relationship between classes

For example

Examples of LGTeacher and object teacher, LGPerson and object person mentioned above are shown in the figure below

  • Isa routing chain (two)

    • Teacher’s ISA walking chain:Teacher (subclass object) --> LGTeacher (subclass) --> LGTeacher (child metaclass) --> NSObject --> NSObject
    • Isa bitmap for Person:Person --> LGPerson --> LGPerson --> NSObject --> NSObject --> NSObject --> NSObject
  • Superclass Chain (two)

    • Class inheritance chain:LGTeacher --> LGPerson --> NSObject --> nil
    • Metaclass inheritance chain:LGTeacher --> LGPerson --> NSObject --> nil

objc_class & objc_object

Now that we’re clear about isa, we have a new problem: why do objects and classes have ISA attributes? There are two struct types to mention: objc_class & objc_Object

On the basis of these two structures, the above problems are explored below.

In the previous article, isa and class association principle, using clang to compile the main.m file, from the compiled c++ file can see the following c++ source code

The underlying compilation of NSObject is the NSObject_IMPL structure,

  • Among themClassisisaThe type of pointer is defined byobjc_classDefined type,
  • whileobjc_classIt’s a structure. In iOS, all of themClassAre based onobjc_classCreated for the template
struct NSObject_IMPL {
    Class isa;
};

typedef struct objc_class *Class;
Copy the code

Search the objC4 source code for the objC_class definition, which has two versions

  • The old versionLocated in theruntime.h, has been abolished

The new version of objc-runtime-new.h is the latest optimized version of objC4-818.2 and will be used to analyze the structure of the following classes.

  • From the new definition, you can see that the objc_class structure type is inherited from objc_Object,

  • Search the objC4 source for objc_object (or objc_object {, there are also two versions of this type

  • One is located at objc.h, which has not been abolished, and as you can see from the compilation of main.cpp, this version of objc_Object is used

  • Located in theobjc-privat.h

Here is the compiled definition of objc_Object in main.cpp

struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};
Copy the code

【 QUESTION 】 What is the relationship between objc_class and objc_object?

Through the above source search and the underlying compiled source code in main.cpp, there are the following notes:

  • The structure type objc_class inherits from objc_Object, which is also a structure and has an ISA property, so objc_class also has an ISA property

  • In mian. CPP, the ISA in NSObject is defined at the bottom by Class, where the underlying encoding of Class comes from the objc_class type, so NSObject also has isa attributes

  • NSObject isa class that initializes an instance object, objc, which satisfies the properties of objc_object (that is, it has the isa property), mainly because isa is inherited from objc_class by NSObject, Objc_class inherits from Objc_Object, which has an ISA property. So objects have an ISA, and ISA stands for pointing, from the current objc_Object

  • Objc_object is the current root object, and all objects have the property objc_Object, which has the ISA property

【 baidu interview question 】 Objc_object and object relationship

  • All of theobjectAre based onobjc_objectAs a templateinheritanceCome over
  • All objects are fromNSObject(OC), but the one that really gets to the bottom is oneObjc_object (C/C + +)Struct type of

【 Summary 】 The relationship between objC_object and object is inheritance

conclusion

  • All objects + classes + metaclasses have isa attributes

  • All objects are inherited from objc_Object

  • In a nutshell, everything is an object and everything comes from objc_Object. There are two conclusions:

    • All toobjc_objectCreated for the templateobject, there areisaattribute
    • All toobjc_classIs created as a templateclass, there areisaattribute
  • At the structural level, it can be popularly understood as the docking between upper OC and bottom OC:

    • The lowerIs through theThe structure of the bodyThe definition of theThe template, e.g.Objc_class, objc_object
    • The upperIt’s through the bottom layerThe template to createSome types of, e.gLGPerson

The overall relationship of objc_class, objC_Object, ISA, Object, NSObject, etc., is shown in the following figure

Class structure analysis

It mainly analyzes what is stored in the class information

Supplementary knowledge – Memory offset

Before analyzing the class structure, you need to understand the memory offset because it is used when accessing the class information

【 Ordinary pointer 】

  • A and B both point to 10, but A and BDifferent addressThis is a copy of theCopy the value, also known asDeep copy
  • The addresses of A and B differ by 4 bytes, depending on the type of a and B

The address points as shown in the figure

Object pointer

  • P1 and P2 are Pointers,p1Is pointing to[LGPerson alloc]Create a spatial address, that is, a memory address, same with p2
  • & p1, and p2 isAddresses to Pointers to objects P1 and p2The pointer is zeroThe secondary pointer

The point of the pointer is shown below

Array pointer

The pointer points as follows

Explore what’s in the information

When we explore what’s in the class information, we don’t know what the structure of the class is beforehand, but we can get the first address from the class, and then we can translate the address to get all the values in it, right

Objc_class is defined as follows and has the following properties

struct objc_class : objc_object { // Class ISA; //8 bytes Class superclass; //Class type 8 bytes cache_t cache; // formerly cache pointer and vtable class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags //.... Method part omitted, not posted}Copy the code
  • Isa property: Inherited isa from objc_Object, 8 bytes

  • Superclass property: Class type, Class is defined by objC_Object, is a pointer, 8 bytes

  • Cache attributes: This is not known from the class_data_bits_t type. Class_data_bits_t is a structure type, and the size of the structure is determined by the internal attributes. The structure pointer is 8 bytes

  • Bits: The bits can be obtained only if the first address is translated by the sum of the memory size of the preceding three attributes

Calculate the memory size of the cache class

Entering the cache_t class (which only displays attributes that are not static, mainly because static attributes do not exist in the structure’s memory), we have the following attributes

  • Calculate the memory size of the first two attributes, in either case, the total memory size is 12 bytes

    • 【 situation 1 】 If process

      • bucketsType isstruct bucket_t *, it isStructure pointerThe type,8byte
      • mask 是mask_tType, andmask_t 是 unsigned intAlias, account for4byte
    • 【 situation 2 】 The elseif process

      • _maskAndBuckets 是uintptr_tType, it’s aPointer to the, accounting for8byte
      • _mask_unused 是mask_tType, andmask_t 是 uint32_tAlias for the type definition, accounting4byte
  • _flags is the uint16_t type, uint16_t is an alias for unsigned short and takes up 2 bytes

  • _occupied is the uint16_t type, which is an alias for the uint16_t unsigned short and is 2 bytes long

The size of the cache class = 12 + 2 + 2 = 16 bytes

To obtain bits

So, to get the contents of bits, you simply shift the first address of the class by 32 bytes

The following is the debugging process using the LLDB command

  • There are two ways to get the first address of a class

    • throughp/x CJLPerson.classGet the first address directly
    • throughx/4gx CJLPerson.classTo print memory information

  • One of thedata()To obtain data, it is provided byobjc_classMethods provided

  • from$2This can be seen in the print result of the pointerbitsIs the information stored in theclass_rw_t, is also a struct type. But we still don’t see itProperty list, method listEtc., need to continue to explore

Explore the property list, or property_list

By looking at the source code of the class_rw_t definition, we found that the structure provides corresponding methods to get the property list, method list, and so on, as shown below

After getting bits and printing the bits information, we continue to explore the list of attributes in bits using the methods provided by class_rw_t. The following is a diagram of the LLDB exploration process

  • The propertoes method in the p $8.properties() command is provided by class_rw_t, and the actual type returned in the method is property_array_t

  • Since list is of type property_list_t, which is a pointer, we get the information in memory by p *$10, and also prove that property_list, the property list, is stored in bits

  • P $11.get(2) : property_list (name, age) property_list (name, age)

【 Question 】 Explore the storage of member variables

Therefore, it can be concluded that property_list has only properties but no member variables. The difference between properties and member variables is that there are no set and GET methods. If there are, they are properties; if not, they are member variables.

So the question is, where are the member variables stored? Why is this the case? Please move to the analysis and exploration at the end of this article

Explore the list of methods, methods_list

Preparation: Add two methods (instance methods & class methods) to the LGPerson mentioned earlier

LLDB debugging is used to get the list of methods, as shown in the figure below

  • Get the list structure of a concrete list of methods by using p $4.methods(), where methods are also provided by class_rw_t

  • The printed count = 5 shows that five methods are stored, and a single method can be retrieved by memory offset p $7.get(I), where I ranges from 0 to 4

  • If you print p $7.get(5) and get the fifth method, you will also get an error indicating that the array is out of bounds

Exploration of new problems

【 Question 】 Explore the storage of member variables

From the above property list analysis, it can be concluded that property_list has only properties, but no member variables. Then the question arises: Where are member variables stored? Why is this the case?

In addition to methods, properties, and protocols, there is also a ro method whose return type is class_ro_t. The ivars attribute is of type ivar_list_t. The ivars attribute is of type Ivar_list_t.

The following is the LLDB debugging process

  • class_ro_tThe properties in the structure are shown below and you want to obtain themivarsWe need roThe first address is shifted by 48byte

As can be seen from the figure, the ivars attribute is obtained, in which count is 2. It is found by printing that there is not only age but also name in the member list, so some conclusions can be drawn as follows:

  • Member variables defined by {} are stored in the bits property of the class. The bits –> data() –>ro() –> ivars is used to get the list of member variables, including the member variables defined by the property

  • Properties defined by @property are also stored in the bits property, and the bits –> data() –> properties() –> list property list contains only properties

【 Problem 】 Explore the storage of class methods

There are only instance methods in the methods list, but no class methods. Where are class methods stored? Why is this the case? Let’s take a closer look

In the first part of this article, we mentioned metaclasses. The isa reference of a class object isa metaclass. Metaclasses are used to store information about a class. We can verify our guess with the LLDB command. The following figure shows the LLDB debugging process

From the printed results of the list of metaclass methods in the figure, we can know that our guess is correct, so we can draw the following conclusions:

  • classtheInstance methodsStored in theClass to the bits propertythroughbits --> methods() --> listTo obtainList of instance methods, e.g.LGPersonOf the classExample method sayHelloIt is stored in theLGPerson type bitsProperty, classMethods listIn addition to includingInstance methods, also includes attributesSet method 和 The get method
  • classtheClass methodStored in theThe bits property of the metaclassthroughBits --> methods() --> listTo obtainList of class methods, e.g.LGPersonIn theClass methods sayByeIt is stored in theLGPersonOf the classThe metaclass(the name is also LGPerson)bitsProperties of the