isKindOfClassとisMemberOfClassの違いと注意点【Objective-C】

[object isKindOfClass:NSObject.class];
[object isMemberOfClass:NSObject.class];

いずれもオブジェクトが特定のクラスのインスタンスかどうかを判定するためのメソッドですが、判定の度合いが異なります。

「isKindOfClass」は同一または親子関係にあるクラスかどうかを知りたい場合に使い、「isMemberOfClass」は完全に自身と同一のクラスかどうかを知りたい場合に使います。

isKindOfClass

  • クラスが一致する場合はYESを返す
  • 親クラスと一致する場合はYESを返す
  • 小クラスとの一致は考慮しない

isMemberOfClass

  • クラスが一致する場合はYESを返す
// @interface MyURL : NSURL @end

/* isKindOfClass */
NSURL *url = [NSURL URLWithString:@"http://marycore.jp"];
[url isKindOfClass:NSNumber.class]; // NO  (無関係なクラス)
[url isKindOfClass:NSObject.class]; // YES (親クラス)
[url isKindOfClass:NSURL.class];    // YES (同クラス)
[url isKindOfClass:MyURL.class];    // NO  (子クラス)
 
/* isMemberOfClass */
NSURL *url = [NSURL URLWithString:@"http://marycore.jp"];
[url isMemberOfClass:NSNumber.class]; // NO  (無関係なクラス)
[url isMemberOfClass:NSObject.class]; // NO  (親クラス)
[url isMemberOfClass:NSURL.class];    // YES (同クラス)
[url isMemberOfClass:MyURL.class];    // NO  (子クラス)

isMemberOfClassの注意点

なお、NSString型やNSNumberクラス等の標準クラスではisMemberOfClassが意図したように動作しません。

[@"" isMemberOfClass:NSString.class]; // NO (?!)

NSString型のインスタンスは__NSCFStringNSTaggedPointerStringという特殊なインスタンスで表現されることがあるためです。

コンクリートクラスと呼ばれる特殊なクラスから生成されたインスタンスでも同様の結果となります。コンクリートクラス、もといクラスクラスタを用いた設計は、JSON系ライブラリ等でも頻繁に用いられているため、特に注意しておく必要があります。

isMemberOfClassのほうが高速なのは確かですが、特殊なクラスやコンクリートクラスが交じる可能性があるインスタンスに対してはisKindOfClassを使うようにしましょう。自作クラスであればそれほど気にする必要はありませんが、将来的な拡張を見越してisKindOfClassで統一するのも手です。


私「[a isMemberOfClass:b]って結局a.class == bとやってることは同じだよね?」
Objective−C「えへへ・・・///」
私「えへへ、じゃなくて!」

広告
広告