isKindOfClassおよびisMemberOfClass

日常の開発では-isKindOfClass、オブジェクトがクラスであるかその親クラス(継承チェーン上のクラス)であるかを判断するためによく使用されますが、使用されることはめったにありません-isMemberOfClass。それらの違いは何ですか。この記事ではobjc源码常にそれらの違いを分析します。

1.ケース

で新しいクラスを作成し(この記事objc源码を参照してください、から継承し、実装を空にし、次のように関数を変更します。PersonNSObjecmain

// main.m
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Class objCls = [NSObject class];
        BOOL ret1 = [(id)objCls isKindOfClass:[NSObject class]];
        BOOL ret2 = [(id)objCls isMemberOfClass:[NSObject class]];
        NSLog(@"\nret1 = %d\nret2 = %d", ret1, ret2);
        
        Class pCls = [Person class];
        BOOL ret3 = [(id)pCls isKindOfClass:[Person class]];
        BOOL ret4 = [(id)pCls isMemberOfClass:[Person class]];
        NSLog(@"\nret3 = %d\nret4 = %d", ret3, ret4);
        
        NSObject *obj = [[NSObject alloc] init];
        BOOL ret5 = [obj isKindOfClass:[NSObject class]];
        BOOL ret6 = [obj isMemberOfClass:[NSObject class]];
        NSLog(@"\nret5 = %d\nret6 = %d", ret5, ret6);
        
        Person *person = [[Person alloc] init];
        BOOL ret7 = [person isKindOfClass:[Person class]];
        BOOL ret8 = [person isMemberOfClass:[Person class]];
        NSLog(@"\nret7 = %d\nret8 = %d", ret7, ret8);

    }
    return 0;
}
复制代码

プログラムを実行した後のコンソール出力は次のとおりです。

2020-02-08 20:27:45.681409+0800 objc-debug[1378:33202] 
ret1 = 1
ret2 = 0
2020-02-08 20:27:45.682017+0800 objc-debug[1378:33202] 
ret3 = 0
ret4 = 0
2020-02-08 20:27:45.682176+0800 objc-debug[1378:33202] 
ret5 = 1
ret6 = 1
2020-02-08 20:27:45.682305+0800 objc-debug[1378:33202] 
ret7 = 1
ret8 = 1
Program ended with exit code: 0
复制代码

この結果は少し奇妙に見えるかもしれませんので、見てください...


第二に、ソースコードの解釈

上記のコードは、実際には4つのメソッド、クラスメソッドを呼び出します。

  • +isKindOfClass:
  • +isMemberOfClass:

およびインスタンスメソッド:

  • -isKindOfClass:
  • -isMemberOfClass:

1+isKindOfClass:

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
复制代码

object_getClass(self)つまりself->isa、ソースコードからわかるように、[NSObject class]それはNSObjectクラスそのものであり、そのisa方向はであり、から継承される継承チェーンにNSObject元类沿ってNSObject元类段階的に判断されます。したがって、NSObject元类NSObject

BOOL ret1 = [(id)objCls isKindOfClass:[NSObject class]]
复制代码

このコード行の判断パスはNSObject元类->NSObjectであり、これはそれ自体と同じであるため、ret1 = YES

Person->isaはいPerson元类Person元类から継承されNSObject元类、からNSObject元类継承されNSObject、その後

BOOL ret3 = [(id)pCls isKindOfClass:[Person class]];
复制代码

このコード行の判断パスはPerson元类-> NSObject元类-> NSObject、つまりPerson != NSObjectret3 = NOです。

2+isMemberOfClass:

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}
复制代码

直接判断のポイントがisa入力パラメータと等しいかどうかはNSObject元类当然等しくないNSObjectので、ret2 = NO、にPerson元类等しくありませんPersonret4 = NO

3-isKindOfClass:

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
复制代码

これとクラスメソッドの唯一の違いは、ループ条件の初期値がではtcls = [self class]なく、であることです。tcls = object_getClass(self)

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}
复制代码

classメソッドは、メソッドとインスタンスメソッドも分類します。クラスメソッドは直接self戻り、インスタンスメソッドはself->isaポインタを返します。ここでは、インスタンスオブジェクトを使用して呼び出しているため、インスタンスメソッドが実行され-class、実際にはクラスメソッドの実装と同じになり+isKindOfClass:ます。

BOOL ret5 = [obj isKindOfClass:[NSObject class]];
复制代码

obj->isaつまりNSObject、このコード行の判断パスはNSObject->nilであり、最初のステップは、をヒットすることret5 = YESです。

BOOL ret7 = [person isKindOfClass:[Person class]];
复制代码

person->isaつまりPerson、このコード行の判断パスはPerson-> NSObject->nilです。ret7 = YES

4-isMemberOfClass:

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
复制代码

それは、それがself->isa入力パラメータと等しいかどうかを判断することです。

BOOL ret6 = [obj isMemberOfClass:[NSObject class]];
复制代码

このコード行の翻訳は、実際にはobj->isa== NSObjectret6 = YESです。

BOOL ret8 = [person isMemberOfClass:[Person class]];
复制代码

同様にperson->isa== Person、。ret8 = YES

3.まとめ

+isKindOfClass:合計はポインタ-isKindOfClass:から判断され、それらのいずれかが入力パラメータと等しくなるまで継承チェーンをたどり、その後、を返します。そして、それが入力パラメータと等しいかどうかを直接判断します。最後に、この古典的なポインティングと継承の関係図を配置します。self->isaself->isaNSObjectYES
+isMemberOfClass:-isMemberOfClass:self->isa
isa

おすすめ

転載: juejin.im/post/7084154382903672840