In previous posts, I have covered the underlying structure of a class, the bit flow of ISA, the inheritance chain of metaclasses, object methods, the location of class methods, and how to obtain members and attributes through LLDB, object methods, and class methods.

IOS Infrastructure like Discovery (part 1)

IOS infrastructure like Discovery (middle)

This blog is mainly about additions and extensions.

Member variables and attributes

If you’re an iOS programmer who’s been around a long time, you know, before iOS5, you used to see a member variable in curly braces, and at sign property declaration, and then at sign implementation, at sign synthesize.

In fact, the root cause of this situation is apple’s conversion of the default compiler from GCC to LLVM(Low Level Virtual Machine), which no longer requires the declaration of instance variables for properties.

Before the changes are made, the normal way to write a property requires the member variable + @property + @synthesize the member variable in three steps. After switching to LLVM, the compiler generates an instance variable starting with an underscore when no new instance variable is found during compilation. So now we don’t have to declare an instance variable again.

now@propertyDeclared properties don’t just generate one for us by default_ typeIs also generatedsetter/getterMethods.

  • Property = underlined member variable + setter + getter methods
  • Instance variables: Special member variables (instantiation of a class)

As can be verified from the underlying clang source code above, the @property declaration property generates a member variable of type _ by default, and also generates setter/getter methods.

objc_setProperty

However, we found a problem with the underlying source code above. Some set methods fetch properties through objc_setProperty, and some by memory translation. What is the reason for this? By comparing the underlying source code with and without copy in different property Settings, you can find the reason for the copy setting problem! So to test this, let’s go to the bottom!

LLVM

Then we go tollvmTake a look inside the source code,objc_setPropertyHow do you know to LLVM is not to objC source code to see? See the analysis belowFirst of all, at the bottom level, apple’s source code is fixed and does not change (by “constant” I mean it does not change according to your code, because the underlying logic is already written). At the top, we, the developers, would write a lot of properties, and there would be all kinds of weird code, there would be all kinds ofsetForm code, for exampleSetName, setAge, setXX. And so on.

It’s just that the _cmd method name is different for the compiler, and that requires an intermediate layer to handle all of these quirks in order to interact with the underlying logic, because the underlying logic is encapsulated and cannot be changed dynamically. Objc_setProperty can’t be done at runtime, it can only be done at compile time, so let’s go to LLVM!

What’s the connection between the upper layer and objc_setProperty?

We are inllvmI found it in there.getGetPropertyFnThis is a function that gets createdCreateRuntimeFunctionAnd there areobjc_setPropertyThis parameter. So why create it? Moving on, where is it calledNow that it’s called, it must be conditional. It’s true. It’s becausepropertythecopy? If we find the condition, we can work backwardsobjc_setPropertyThe effect of. Keep readingCan you see anything in the code above? There’s a policy for the property IMPPropertyImplStrategySo keep lookingSee? IfIsCopyIs true isKind = GetSetProperty, this also verified the blog at the beginning of the conjecture, only attribute inside with copy modification, will haveobjc_setProperty.

The code gets information about the class

In the previous blog, we learned that you can get the class information from the console through the LLDB, so let’s get it from the code.

class_copyMethodList

void lgObjc_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];
        // Get the method name
        NSString *key = NSStringFromSelector(method_getName(method));
        
        LGLog(@"Method, name: %@", key);
    }
    free(methods);
}
Copy the code

class_getInstanceMethod

// Get the instance method
void lgInstanceMethod_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));
    
    LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
Copy the code

class_getClassMethod

// Get the class method
void lgClassMethod_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));

// - (void)sayHello;
// + (void)sayHappy;
    Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
    Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
    
    LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
Copy the code

class_getMethodImplementation

void lgIMP_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));/ / 0
    // sel -> imp method search process imp_farw
    IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy)); / / 0
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));

    NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
    NSLog(@"%s",__func__);

}
Copy the code

Code test validation

IMP,SEL

  • SEL: pointer to a class member method, but different from the function pointer in C, the function pointer directly stores the address of the method, but SEL is only the method number.
  • IMP: a function pointer that holds the address of the method
  • The relationship between SEL and IMP is: SEL is equivalent to the catalog title of the book, IMP is the page number of the book, and the function is the corresponding content of the specific page number.

extension

Now that we’ve covered so many topics, let’s look at the following interview question

    BOOL re1 = [(id) [NSObject class] isKindOfClass:[NSObject class]].BOOL re2 = [(id) [NSObject class] isMemberOfClass:[NSObject class]].BOOL re3 = [(id)[JPPerson class] isKindOfClass:[JPPerson class]].BOOL re4 = [(id)[JPPerson class] isMemberOfClass:[JPPerson class]].NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n,%hhd,%hhd",re1,re2,re3,re4,re9,re10);

    BOOL re5 = [(id) [NSObject alloc] isKindOfClass:[NSObject class]].BOOL re6 = [(id) [NSObject alloc] isMemberOfClass:[NSObject class]].BOOL re7 = [(id)[JPPerson alloc] isKindOfClass:[JPPerson class]].BOOL re8 = [(id)[JPPerson alloc] isMemberOfClass:[JPPerson class]].NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

Copy the code

Code run result

+ isKindOfClass

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
Copy the code

– isKindOfClass

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
Copy the code

+ isMemberOfClass

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
Copy the code

– isMemberOfClass

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
- (Class)class {
    return object_getClass(self);
}
Copy the code

Analysis of the

  • re1The incoming isNSObjectClass, getThe metaclasswithNSObjectThe parent of the metaclass isNSObjectEqual to the value passed in, returnstrue
  • Re2 isNSObjectClass calls class methodsisMemberOfClasswithNSObject classBy comparison, obviously,NSObject metaclasswithNSObjectDoes not equal itself, so returnsfalse
  • re3The incoming isJPPersonClass, getThe metaclasswithJPPersonThe parent of the metaclass isNSObjectThe metaclass of, again unequal to the value passed in, continues upwardNSObject metaclassThe parent classNSObjectStill no. It’s just up therenil, and finally returnsfalse

The JPPerson metaclass is not equal to the JPPerson metaclass, so return false.

  • re5The incoming isNSObjectGets the class of the object, andNSObjectEqual, returntrue
  • re7The incoming isJPPersonGets the class of the object, andJPPersonEqual, returntrue

-re8 is an instance of JPPerson that calls the instance method isMemberOfClass compared to the JPPerson class. Obviously they are the same, so returns true

More content continues to be updated

🌹 please move your little hands and give a thumbs-up 👍🌹

🌹 like can come a wave, collect + attention, comment + forward, so as not to find me next time, ha ha 😁🌹

🌹 welcome everyone to leave a message exchange, criticism and correction, learn from each other 😁, improve themselves 🌹