This is the 5th day of my participation in the August More Text Challenge

First take a look at apple WWDC2020 video on runtime optimization

One, memory – likerodata

The last chapter looked at class properties and methods, but what about member variables?Through printclass_rw_ttheproperties()Finding only class attributes but no member variables, we passWWDC2020 about Runtime optimizationThe video explains thatMember variablesinroIn the. whileclass_rw_tAnd you can see that in the structurerothegetmethods

printclass_rw_tIn theroAnd got aclass_ro_t.class_ro_tYou can see that there is aivarsProperty, print it out and you get oneivar_list_t Then through theThe get methodYou can find all of themMember variables

Member variables and attributes and encoding

Member variables and attributes

We found member variables in the previous section. How are member variables and attributes represented underneath?

throughclangCommands are compiled to the underlying levelC++fileYou can see that in the underlying C++ there are no attributes, but allLRPerson_IMPLStructure, and properties are converted to bands_Form.At the same time, properties in OC are generated in the underlying C++getandsetMethod, while member variables do not

2, coding

In C++ source code, you can see these symbols. What are these symbols? What does the stand for mean?

These are all codes that can pass throughcommand + shift + 0Search,ivar_getTypeEncoding, click on theType EncodingsView detailed memory. The enclosedType Encodings addresses

For example, “setName:”, “v24@0:8@16” Said void 2, a total of 24 function parameters in the memory size 3 and @ the first parameter (hidden) parameters namely self 4, 0 start from 0 # 5, : the second parameter (hidden) parameters SEL 6, 8 from 8 position 7, @ the third parameter 8, 16, starting from the 16th position

3, add

Instance variables: Special member variables (object type declaration, instantiation of a class), non-basic data classes

Three,setter,getterThe underlying principles of the method

1.A setter method

In the underlying C++ file just compiled, you can see the properties in OCgetandsetMethods. But a closer look revealsnickNamethesetAnd the way to do that is byobjc_setPropertyTo achieve, whilenameandanamethesetThe method is implemented by memory translation assignment

fromllvmLook in the source codeobjc_setProperty, found ingetSetPropertyFnCreated in theKeep lookinggetSetPropertyFn Keep lookingGetPropertySetFunction foundGetPropertySetFunctionThe call is in aswitchthecaseMedium, checkPropertyImplStrategytype PropertyImplStrategyThe implementation of theYou can see it hereIsCopyIf it isIsAtomicThe assignment isGetSetPropertyOtherwise, forSetPropertyAndExpressionGet, socopyIs to affect useobjc_setPropertyImportant factors, through the following code to verify

@property (nonatomic.copy) NSString *nickName;
@property (atomic, copy) NSString *nickName1;
@property (nonatomic) NSString *nickName2;
@property (atomic) NSString *nickName3;
Copy the code

withclangCommand compiled intoC++Source code can be found withcopyModifies the attributes underlying the passobjc_setPropertyimplementationsetMethod, and others via memory translation assignment

inobjcLook at the source codeobjc_setPropertyFunction implementation You can see the underlying callcopyWithZone. socopyModifier properties copy memory, other modifiers do not copy memory translation

2,gettermethods

In the inquirysetMethod, we can see somegetMethods byobjc_getPropertyImplementation, while some are directreturnA memory shifted valuellvmContinue to exploreobjc_getProperty.PropertyImplStrategyA type ofGetSetProperty ultimatelygetterThe determining factor for the method is this codeThis code is also clearly commented

  • If it iscopyModified property, used withsetProperty
  • If the property is still usedatomicEmbellish, then usegetProperty

Class method storage API way parsing

There are two methods in a class

- (void)sayHello;
+ (void)sayHappy;
Copy the code

1.class_getInstanceMethod

void lrInstanceMethod_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);
}
Copy the code

Output result:

0x1000081c0 - 0x0 - 0x0 - 0x100008158
Copy the code

Results analysis:

  • sayHelloObject methods exist in classes
  • sayHappyClass methods exist in metaclasses

2,class_getClassMethod

void lrClassMethod_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);
}
Copy the code

Output result:

0x0 - 0x0 - 0x100008158 - 0x100008158
Copy the code

class_getClassMethodIs to obtainClass methodAnd, at the bottom level, getObject methods of metaclasses method4The incoming isThe metaclass, the underlying code will determine if it is already a metaclassDirect returnOtherwise return the metaclass An object is an instance of a class, a class is an instance of a metaclass, and there are no class methods at the bottom, only object methods

3,class_getMethodImplementation

void lrIMP_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);
}
Copy the code

Output result:

0x100003ae0 - 0x7fff6e3b7580 - 0x7fff6e3b7580 - 0x100003b20
Copy the code

According to theclass_getInstanceMethodAnalysis of, hereimp2 imp3There should be no implementation, but the output should have value. This involves the method lookup process, which returns one even if none is found_objc_msgForward. More on the message forwarding mechanism later

4,isKindOfClass,isMemberOfClass

void kindOfTest(void) {
    BOOL re1 = [(id) [NSObject class] isKindOfClass:[NSObject class]].BOOL re2 = [(id) [NSObject class] isMemberOfClass:[NSObject class]].BOOL re3 = [(id)[LRPerson class] isKindOfClass:[LRPerson class]].BOOL re4 = [(id)[LRPerson class] isMemberOfClass:[LRPerson class]].NSLog(@" re1 :%d\n re2 :%d\n re3 :%d\n re4 :%d\n",re1,re2,re3,re4);

    BOOL re5 = [(id) [NSObject alloc] isKindOfClass:[NSObject class]].BOOL re6 = [(id) [NSObject alloc] isMemberOfClass:[NSObject class]].BOOL re7 = [(id)[LRPerson alloc] isKindOfClass:[LRPerson class]].BOOL re8 = [(id)[LRPerson alloc] isMemberOfClass:[LRPerson class]].NSLog(@" re5 :%d\n re6 :%d\n re7 :%d\n re8 :%d\n",re5,re6,re7,re8);
}
Copy the code

Output result:

 re1 :1
 re2 :0
 re3 :0
 re4 :0
 
 re5 :1
 re6 :1
 re7 :1
 re8 :1
Copy the code

According to theisKindOfClass,isMemberOfClassSource code analysis:

  • + (BOOL)isKindOfClass:(Class) CLS Class method. Get the metaclass of the class, judge whether the metaclass and parameter are the same, if not, cycle to judge the parent class. In RE1, NSObject is the root class, and the parent class of the root metaclass is the same as the argument, return YES. In RE3 you go from the LRPerson metaclass to the parent class NSObject to nil, which is different from the argument LRPerson class. So return NO.

  • – (BOOL)isKindOfClass:(Class) CLS object method. Get the class of the current object, judge whether the class and parameter are the same, if not, loop to judge the parent class. The NSObject object in RE5 has the same class as the parameter NSObject, returning YES. The LRPerson object in RE7 has the same class as the parameter LRPerson class and returns YES.

  • + (BOOL)isMemberOfClass:(Class) CLS Class method. Get the metaclass of the class, check whether the metaclass and argument are the same, and return NO. The LRPerson metaclass in RE4 is not the same as the LRPerson class and returns NO.

  • – (BOOL)isMemberOfClass:(Class) CLS object method. Gets the class of the object, determines whether the class and argument are the same, and returns YES for NSObject. The LRPerson class in RE8 is the same as the LRPerson class and returns YES.

It can also be found through compilationisKindOfClass,isMemberOfClassIn the bottom, we goobjc_opt_isKindOfClass