Hi 👋

  • 📚 Personal site: lab.lawliet
  • 📦 Technical documentation
  • 🐙 making
  • Wechat: RyukieW

My apps

Mine Elic endless sky ladder Dream of books
type The game financial
AppStore Elic Umemi

Think about it. What does the following code output?

BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [[RYModel class] isKindOfClass:[RYModel class]];
BOOL result4 = [[RYModel class] isMemberOfClass:[RYModel class]];

NSLog(@"Class\n %hhd \n %hhd \n %hhd \n %hhd", result1, result2, result3, result4);

BOOL result5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL result6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL result7 = [[RYModel alloc] isKindOfClass:[RYModel class]];
BOOL result8 = [[RYModel alloc] isMemberOfClass:[RYModel class]];

NSLog(@"Instacne\n %hhd \n %hhd \n %hhd \n %hhd", result5, result6, result7, result8);
Copy the code

Results:

Class
 1 
 0 
 0 
 0
Instacne
 1 
 1 
 1 
 1
Copy the code

If you take the code literally, your answer should be different. We from the source layer to understand it, the source code is not long, very easy to understand.

A, isKindOfClass

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

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

1.1 Flowchart -Class

  • The [NSObject class]RootClass
    • RootClass -(ISA)> RootMetaClass -(superClass)> RootClass
    • true
  • [RYModel class]
    • [RYModel class] -(ISA)> RYModelMetaClass -(superClass)> RootMetaClass -(superClass)> RootClass -(superClass)> nil
    • false

1.2 Flowchart-Instance

  • NSObjectInstance
    • NSObjectInstance -(class)> RootClass
    • true
  • RYModelInstance
    • RYModelInstance -(class)> RYModelClass
    • true

Second, the isMemberOfClass

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

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

So that’s pretty simple, so I won’t go into it.

You think this is the end?

If you look at this and you think it’s okay? That’s a problem…

We run OC source code, two breakpoints.

+/- (Bool)isKindOfClass:(Class) CLS

3.1 the assembly

Through breakpoint assembly, we found the instruction objc_opt_isKindOfClass where we called isKindOfClass

->  0x10000381c <+332>: mov    rdi, qword ptr [rip + 0x4f7d]; (void *)0x0000000100008808: RYModel
    0x100003823 <+339>: call   0x100003b42               ; symbol stub for: objc_opt_class
    0x100003828 <+344>: mov    rbx, rax
    0x10000382b <+347>: mov    rdi, qword ptr [rip + 0x4f6e]; (void *)0x0000000100008808: RYModel
    0x100003832 <+354>: call   0x100003b42               ; symbol stub for: objc_opt_class
    0x100003837 <+359>: mov    rdi, rbx
    0x10000383a <+362>: mov    rsi, rax
    0x10000383d <+365>: call   0x100003b48               ; symbol stub for: objc_opt_isKindOfClass
Copy the code

3.2 objc_opt_isKindOfClass

// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    / / found empty
    if (slowpath(! obj))return NO;
    Class cls = obj->getIsa(a);if (fastpath(! cls->hasCustomCore())) {
        for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    // This can be ignored
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
Copy the code

And when we break here, we find that we do enter here. And the Class and Instance methods go here.

The compiler optimizes this by replacing it with the more efficient objc_opt_isKindOfClass.

Added: slowpath & Fastpath

These two macro definitions are often encountered during daily reading of OC source code. What does it mean?

// X is likely to be true, and fastPath can be abbreviated to truth judgment
#define fastpath(x) (__builtin_expect(bool(x), 1)) 
// slowpath is likely to be false
#define slowpath(x) (__builtin_expect(bool(x), 0)) 
Copy the code

The __builtin_expect directive was introduced by GCC

  • Purpose: The compiler can optimize code to reduce performance degradation caused by instruction jumps. Performance optimization
  • What it does: allows the programmer to tell the compiler which branches are most likely to execute.
  • The instruction is written as follows:__builtin_expect(EXP, N). So the probability that e to the EXP is equal to N is high.
  • fastpathIn the definition__builtin_expect((x),1)It means that x is more likely to be true; That is, there is a greater chance of executing the if statement
  • slowpathDefinition of the__builtin_expect((x),0)That means it’s more likely that the value of x is false. You have a better chance of executing the else statement
  • In daily development, you can also optimize the compiler to achieve performance optimization by setting the path as follows:Build Setting –> Optimization Level –> Debug –> Change "None" to "fastest" or "smallest"