This article, the eighth in the Objective-C series, focuses on the underlying structure of OC objects and their classification: instance objects, class objects, and metaclass objects.

  • Objective C (7) Object memory analysis
  • Objective C (8) The nature and classification of objects
  • Objective-c (9) KVC and KVO
  • Objective-c (10) Category
  • Objective-c load and Initialize
  • Objective-c (12) Associative objects

After the objective-C (7) object memory analysis, we learned that a class is stored in memory.

However, we only analyzed the member variables and attributes of the class. We know that an OC object also includes extremely important information such as methods and protocols. So where are they, how are they stored and how are they used?

This paper further analyzes the classification of Objective-C class system and its complete distribution in memory.

To this end, we need to do some preparatory work first.

A, preparation,

1.1 Object Classification

Objective-c objects, OC objects for short, fall into three main categories:

  • Instance object (instance object)

  • Class object (Class object)

  • Meta-class objects (metaclass objects)

We conducted tests on three types of objects in OC, and the test results are as follows:

From the above figure, we can draw the following conclusions:

  • There can be more than one instance object: for each alloc object, one instance object is created;
  • There can be only one class object: the class object of different instance objects is the same;
  • There can be only one metaclass object: there can be only one metaclass object for different instance objects (class objects);

So test code in a few methods, the following is also briefly described, part of the source code project -BFOCClass classification -01.

1.1.1 [NSObject class]

Mm: in NSObject.

+ (Class)class {
    return self;
}
Copy the code

Returns the class object (metaclass object) itself.

So, [[[NSObject Class] class] returns an NSObject class object no matter how many times class is called.

1.1.2 [person1 class]

Returns the class object of the instance object

- (Class)class {
    return object_getClass(self);
}
Copy the code

According to (2),

  • [person1 class] : returns the object that isa points to in person1, which is the BFPerson class object;

1.1.3 objc_getClass

This method is very similar to object_getClass in terms of the method name.

  • Parameter: string class name;
  • Returns: the corresponding class object.
Class objc_getClass(const char *aClassName)
{
    if(! aClassName)return Nil;
    // NO unconnected, YES class handler
    return look_up_class(aClassName, NO.YES);
}
Copy the code

1.1.4 object_getClass

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
Copy the code

Return the object referred to by isa in the passed obj. The passed obJ may be an instance object, a class object, or a meta-class object

The return value corresponds to:

A) If it is instance, return the class object

B) If it is a class object, return meta-class object

C) If it is a meta-class object, return the meta-class object of NSObject

So in the above test:

  • Object_getClass (person1) : returns the class object;

  • Object_getClass (personClass5) : returns a meta-class object;

1.1.5 class_isMetaClass

Returns whether it is a meta-class object.

1.2 Some constructs from source code

We will extract some of the structure from the source code for the rest of the argument.

1.2.1 NSObject

NSObject is derived from the source code, and its first member variable is isa. The Class structure’s first member variable name is also ISA.

Isa contains the address where the (meta) class information is stored.

1.2.2 class_rw_t

Class_rw_t and class_ro_t are structures that store class information, including member variables, attribute list, protocol list, and method list. The details are as follows:

Currently, we class_ro_t the properties, methods, and protocols that are determined at compile time for the current class.

Class_rw_t is where, at runtime, the Runtime reloads the attributes, methods, protocols, and so on of the current class layout.

1.2.3 method_t

  • method_tIs the lowest level structure of a method.
  • method_list_t
    • List of methods, one-dimensional array
    • The internal storagemethod_t
    • class_ro_tA member variable in.
  • method_array_t
  • Again, it’s a list of methods, but it’s a two-dimensional array
  • The internal storagemethod_t
  • class_rw_tMember variables in;

The relationship among the three is as follows:

Property and protocol are similar.

Why there are one – and two-dimensional arrays will be discussed in more detail in a future article.

1.property_t

The structure of property_array_t and property_list_t is similar to the array of method above. They are two-dimensional and one-dimensional arrays respectively.

struct property_t {
    const char *name;  		 / / the property name
    const char *attributes;  // A string indicating the properties of the property
};
Copy the code

If the attribute name is NAME and the type is NSString, the corresponding attributes are: T@”NSString”,C,N,V_name

1.2.5 protocol_t

Protocol_array_t and protocol_list_t are two and one dimensional arrays of protocol_T, respectively.

Similarly, we look at the protocol_t structure:

struct protocol_t : objc_object {
    const char *mangledName;
    struct protocol_list_t *protocols;
    method_list_t *instanceMethods;
    method_list_t *classMethods;
    method_list_t *optionalInstanceMethods;
    method_list_t *optionalClassMethods;
    property_list_t *instanceProperties;
    uint32_t size;   // sizeof(protocol_t)
    uint32_t flags;
    // Fields below this point are not always present on disk.
    const char **_extendedMethodTypes;
    const char *_demangledName;
    property_list_t *_classProperties;
};
Copy the code

1.2.6 ivar_t

We find that for member variables, there is only ivar_list_t, not ivar_array_t.

From this we can see that even the Runtime cannot add a member variable to a class at runtime.

struct ivar_t {
    int32_t *offset;
    const char *name;
    const char *type;
    // alignment is sometimes -1; use alignment() instead
    uint32_t alignment_raw;
    uint32_t size;
};
Copy the code

1.3 Memory of the NSObject instance object

We are already familiar with the memory structure of the NSObject instance object. Let’s elaborate on the following points:

  • NSObject instance object has one and only one variable in memory called ISA, and ISA points to NSObject’s class object;

Here, for compile-time ISA, combined with the source code, we get the following:

Runtime ISA:

Memory storage of objects

Above, we did some preparatory work to see how and where NSObject stores the various structures of information.

Now we’re going to make a brief description of the three types.

2.1 the instance objects

Its memory layout is as follows:

The instance object stores information in memory:

  • isaPointer to the
  • Other member variables

2.2 class object

Class objects store information in memory mainly including

  • isaPointer to the
  • superclassPointer to the
  • Class instance method information
  • Class property information
  • Class protocol information (Protocol)
  • Class member variable information (IVAR)

2.3 meta – class object

Meta-class objects have the same memory structure as class objects, but their purpose is different. The information stored in the memory mainly includes

  • isaPointer to the
  • superclassPointer to the
  • Class method information of a class
  • Other values including attributes, protocols, and member variables are NULL

Isa and Superclass

Isa is rarely used in normal development, but I believe many iOS developers are familiar with it.

After learning about NSObject, structures, and objects, Apple provided Cocoa/Cocoa Touch with two Pointers to build a class system: ISA and Superclass. So how do you connect them in series?

Horizontal association: ISA establishes a horizontal association between instance objects, class objects, and meta-class objects of a class to provide guidance for searching for various types of information stored in objects.

Vertical connection: Superclass is the embodiment of inheritance, the most important feature in object-oriented languages. It embodies the relationships between classes, that is, it establishes vertical connections in class diagrams.

Note the distinction: relationships between objects of a class, and relationships between different classes!

3.1 the isa

3.1.1 isa pointer

3.1.2 ISA_MASK

To verify this conclusion, we run project-bfocClass class-01 on the real machine and try to get the BFPerson object and print the relevant address of the class:

BFPerson instance - 0x12fd1f570 0x12fd366e0
BFPerson class - 0x100091e28 0x100091e28 0x100091e28 0x100091e28 0x100091e28 0
BFPerson meta class - 0x100091e00 1 0x100091e28 0
(lldb) x/2xw 0x12fd1f570
0x12fd1f570: 0x00091e2d 0x000001a1
Copy the code

From the print we know:

  • The address of the person1 instance object is 0x12FD1f570
  • The first eight bytes of the address of the person1 object areisa, here is:0x1a100091e2d
  • The BFPerson Class address is 0x100091e28, which is different from 0x1A100091e2D
  • 0x1a100091e2d(isa) & 0x0000000ffffffff8(ISA_MASK) = 0x100091e28

3.2 superclass

3.2.1 class object

3.2.2 meta – class object

3.3 Class diagram system

With this in mind, ISA and SuperClass have teamed up to weave the following class diagram:

3.3.1 contact

  • Isa to

    • The instance ofisaPoint to the class
    • A class ofisaPointing to the meta – class
    • Meta – classisaMeta-class that points to the base class
  • Superclass point to

    • A class ofsuperclassIf a class that points to a parent class does not have a parent class,superclassA pointer to nil
    • Meta – classsuperclassMeta-class that points to the parent classMeta-class of the base classsuperclassClass that points to the base class

3.3.2 Method Invocation

  1. Instance calls the path of an object methodisaFind class, method does not exist, passsuperclassTo find the parent class
  2. Class calls the trace of a class methodisaFind meta-class, method does not exist, passsuperclassTo find the parent class

Code reference BFOCClass classification -01

Inheritance: BFStudent->BFPerson->NSObject

3.3.2.1 case 1

BFStudent *stu = [[BFStudent alloc] init];
[stu test];
Copy the code
  • BFStudent implementation – (void) test; , call BFStudent implementation method;

  • BFStudent not implemented -(void)test; , if BFPerson implementation, call BFPerson implementation;

  • BFStudent and BFPerson are not implemented. If NSObject is implemented, call NSObject.

    • [stu test] [stu test] [stu test] , will compile error, need to change the call method:

      ((* *void(*) (* * * *id**, **SEL**))objc_msgSend)(stu, **@selector**(test));
      Copy the code
      • If NSObject implementation+(void)test;The collapse;
      • If NSObject implementation-(void)test;, the call-(void)test;;
  • [BFStudent test]: unrecognized selector sent to instance

3.3.2.2 case 2

[BFStudent test];
Copy the code
  • BFStudent implementation + (void) test; , the implementation of calling BFStudent;

  • BFStudent not implement +(void)test; , if BFPerson implementation, call BFPerson implementation;

  • BFStudent and BFPerson are not implemented. NSObject is called.

    • Unable to [BFStudent test]; Call, the call method should be changed to:

      Class stuClass = [BFStudent class];
      ((void(*) (id, SEL))objc_msgSend)(stuClass, @selector(test))
      Copy the code
      • If NSObject implementation+(void)test;, the call+(void)test;;
      • If NSObject implementation-(void)test;, the call-(void)test;;
      • If NSObject implementation+(void)test;and-(void)test;, the call+(void)test;;
  • +[BFStudent test]: unrecognized selector sent to instance

3.3.3 analysis

In case 1 and case 2, we can understand most of this, but there is one case. There is a difference.

When neither BFStudent nor BFPerson implements the corresponding object method (class method), they look in NSObject.

  • Object method: NSObject looks for the corresponding object method, fails to find the object method, crashes, see the blue arrow below.
  • Class method: NSObject looks for the corresponding class method, does not find the corresponding class method, and then looks for the corresponding instance method. If neither is found, it crashes, as shown in the yellow arrow below.

4. The complete internal structure of the object

At this point, we’re pretty much done with the object, but we still haven’t looked at the entire internal structure of the object at runtime.

4.1 How To Snoop

There are two ways:

  • Method 1: compile objC source code, directly throughobjc4Source code debugging;
    • For compilation details, please refer to Runtime
  • Method two: abstract [some from the source structure](#2. Some from the source structure) mentioned in the structure, the normal object into the corresponding structure, debugging;

Let’s do method two.

4.2 Find out

  1. The abstracted structure can be downloaded here.

  2. After the import, adjust the compile project to the command line project and change main.m to main.mm to support C++ compilation.

Corresponding project source code.

2 class object

4.2.2 Metaclass objects

Now, do you know the nature of OC objects? How are they classified?

reference

link

  1. objc4
  2. Runtime (a) Introduction to Runtime

The sample code

  1. This article source project –BFOCClass classification – 01
  2. This article source project –BFOCClass classification – 02