IOS & OpenGL & OpenGL ES & Metal

We’ve looked at objects before, so today we’ll look at the classes that create them

First, preparation

Explore the environment: declare a member variable, an attribute, a method, and a class method in LibobJC-779.1 Person (custom class)

#import <Foundation/Foundation.h> #import <objc/runtime.h> @interface Person : NSObject{ NSString *hobby; } @property (nonatomic, copy) NSString *nickName; - (void)sayHello; + (void)sayHappy; @end @implementation Person - (void)sayHello{ NSLog(@"LGPerson say : Hello!!!" ); } + (void)sayHappy{ NSLog(@"LGPerson say : Happy!!!" ); } @end int main(int argc, const char * argv[]) { @autoreleasepool { Person *person = [Person alloc]; Class pClass = object_getClass(person); NSLog(@"%@ - %p",person,pClass); } return 0; }Copy the code

Ii. The Nature of classes: Where do classes come from

In OC, all classes can be received using Class.

1.ClassInherited fromobjc_class

Clang to see where the Class inherits from the underlying compilation:

typedef struct objc_class *Class;
Copy the code

2,objc_classInherited fromobjc_object

Continue with the objc_class:

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

Objc_class has several methods in the source code, most of which are deprecated. We found one that works:

struct objc_class : objc_object { // Class ISA; // Here is a hidden attribute Class superclass; cache_t cache; // formerly cache pointer and vtable class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags...Copy the code

We can see that there isa hidden isa in there, which must be an attribute inherited from the parent class. Let’s look at objc_object to verify this:

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Copy the code

3,Class ISA

Our previous exploration: Isa is isa_t. Why is ISA Class in objc_Object?

In the early days of isa, it was used to return a Class. Later, it was optimized to return nonpointer and pure ISA. This is probably a continuation of the habit. The return value is a strong (Class) type

4,NSObjectwithobjc_objectRelation of (object)

We know that in OC, everything is an object! Objc_object is the father of everything! NSObject is a clone of objc_Object. NSObject should be exactly the same as objc_Object.

@interface NSObject <NSObject> { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-interface-ivars"  Class isa OBJC_ISA_AVAILABILITY; #pragma clang diagnostic pop }Copy the code

Or you could say, objc_Object is C, NSObject is OC, and NSObject is a wrapper around objc_Object, which is still going to be objc_Object when you compile underneath.

  • NSObjectThe essence of the object isobjc_object

5,NSObjectwithobjc_classRelation of (class)

The counterpart to objc_class is actually NSObject Class, which is NSObject. The underlying compilation will become objc_class

  • NSObjectThe essence of class isobjc_class

What is stored in the class structure

A class isa structure containing isa, superClass, cache, bits, etc.

1, Class ISA

Isa Pointers, not only in instance objects, but also in class objects. Account for 8 bytes

2, Class superclass

The superclass parent, class*, is itself a pointer. Account for 8 bytes

3, cache_t cache

To track down the type of the cache_t structure, rather than the structure pointer type (8 bits), we need to calculate:

struct cache_t { struct bucket_t *_buckets; // Struct * type = object, 8 mask_t _mask; // mask_t _occupied; // uint32_t; // void uint32_t;Copy the code

The 16-bit cache_t type

4, class_data_bits_t bits

Bits is actually used to store data. We calculate the memory size in order to offset it in memory, and directly obtain the bits to verify whether the attributes and methods in the previous preparation are stored in the bits.

In objc_class, one method data() is omitted, which is a structure of type class_rw_t

Struct objc_class: objc_object {//··· omit class_data_bits_t bits; class_rw_t *data() { return bits.data(); }}Copy the code

Class_rw_t:

struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint32_t version; const class_ro_t *ro; method_array_t methods; property_array_t properties; protocol_array_t protocols; Class firstSubclass; Class nextSiblingClass; char *demangledName; //···Copy the code

Take a sneak peek at Ro:

struct class_ro_t { uint32_t flags; uint32_t instanceStart; uint32_t instanceSize; #ifdef __LP64__ uint32_t reserved; #endif const uint8_t * ivarLayout; const char * name; method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; const uint8_t * weakIvarLayout; property_list_t *baseProperties; method_list_t *baseMethods() const { return baseMethodList; }};Copy the code

Bits store our methods, properties, protocols, and so on. (Ro also has properties for related information.) We’ll verify this later

Where are the attributes of the class stored

In part 3, we calculate that we can get bits by offsetting the first address by 32 bits. The hexadecimal value of 32 is 0x20, and then (class_datA_bits_t *) is strong, so we can directly LLDB (each time we re-run, the memory address may be different from the last time) :

We see properties in bits! Do our declared attributes and member variables exist here? Print it out:

Property_array_t is actually a two-dimensional array type. We continue to print the information inside)

There are! However, there is no complete information in bits, because there is no place to find the declared member variable.

Open god’s perspective: We read ro! Let’s take a look:

Property –baseProperties:

Member variable –ivars:

Sure enough, I found it all in here!

Where are class methods stored

Class instance methods

Let’s go ahead and look at baseMethodList under RO

A: wow! The list has four types: the instance methods of the class, the setter and getter methods generated by the property, and the C++ methods.

But where are the class methods we declared?

Class method

In the metaclass, let’s verify:

Class method of class, indeed here!

As I said before, everything is an object, and a class is an object, and its instance methods are in a class; That kind of method can be understood as an instance method of a class object, in a metaclass.

6. API verification conjecture

Here you can understand, directly post the source code, interested partners can run by themselves:

#import <Foundation/Foundation.h> #import <objc/runtime.h> @interface Person : NSObject{ NSString *hobby; } @property (nonatomic, copy) NSString *nickName; - (void)sayHello; + (void)sayHappy; @end @implementation Person - (void)sayHello{ NSLog(@"LGPerson say : Hello!!!" ); } + (void)sayHappy{ NSLog(@"LGPerson say : Happy!!!" ); } @end void testObjc_copyIvar_copyProperies(Class pClass){ unsigned int count = 0; Ivar *ivars = class_copyIvarList(pClass, &count); for (unsigned int i=0; i < count; i++) { Ivar const ivar = ivars[i]; Const char*cName = ivar_getName(ivar); NSString *ivarName = [NSString stringWithUTF8String:cName]; NSLog(@"class_copyIvarList:%@",ivarName); } free(ivars); unsigned int pCount = 0; objc_property_t *properties = class_copyPropertyList(pClass, &pCount); for (unsigned int i=0; i < pCount; i++) { objc_property_t const property = properties[i]; / / get nsstrings * propertyName attribute name = [nsstrings stringWithUTF8String: property_getName (property)]; // get property value NSLog(@"class_copyProperiesList:%@",propertyName); } free(properties); } void testObjc_copyMethodList(Class pClass){ unsigned int count = 0; Method *methods = class_copyMethodList(pClass, &count); for (unsigned int i=0; i < count; i++) { Method const method = methods[i]; NSString *key = NSStringFromSelector(method_getName(method)); NSLog(@"Method, name: %@", key); } free(methods); } void testInstanceMethod_classToMetaclass(Class pClass){ const char *className = class_getName(pClass); Class metaClass = objc_getMetaClass(className); Method method1 = class_getInstanceMethod(pClass, @selector(sayHello)); Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello)); Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy)); Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy)); NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4); NSLog(@"%s",__func__); } void testClassMethod_classToMetaclass(Class pClass){ const char *className = class_getName(pClass); Class metaClass = objc_getMetaClass(className); Method method1 = class_getClassMethod(pClass, @selector(sayHello)); Method method2 = class_getClassMethod(metaClass, @selector(sayHello)); Method method3 = class_getClassMethod(pClass, @selector(sayHappy)); Method method4 = class_getClassMethod(metaClass, @selector(sayHappy)); / /? NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4); NSLog(@"%s",__func__); } void testIMP_classToMetaclass(Class pClass){ const char *className = class_getName(pClass); Class metaClass = objc_getMetaClass(className); IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello)); IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello)); IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy)); IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy)); NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4); NSLog(@"%s",__func__); } int main(int argc, const char * argv[]) { @autoreleasepool { Person *person = [Person alloc]; Class pClass = object_getClass(person); testObjc_copyIvar_copyProperies(pClass); testObjc_copyMethodList(pClass); testInstanceMethod_classToMetaclass(pClass); testClassMethod_classToMetaclass(pClass); NSLog(@"Hello, World!" ); } return 0; }Copy the code

Six, summarized

Today through the LLDB step by step debugging, although a little tedious, but also verified a lot of only know one of the two:

  • The essence of a class is a structure. (All pairs are objects. The essence of a class is an object.

  • Class structures include ISA, superClass, cache, and bits

  • Class is an objc_class type

  • Objc_class inherits from objc_Object

  • Class attributes, member variables, methods, protocols, and so on are stored in the class_ro_t structure

  • The class methods of the class exist in the class_ro_t metaclass

  • Classes and metaclasses are created at compile time (verified at the end of isa exploration)