isa / isMemberOfClass / isKindOfClass

先来做几道题目,做的出来的就不要往下看了。


@interface Animal : NSObject

@end
@implementation Animal

@end

@interface Dog  : Animal

@end

@implementation Dog

@end

@interface Demo40ViewController ()

@end

@implementation Demo40ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Animal *p     = [[Animal alloc] init];
    
    BOOL isEqual  = [p isKindOfClass:[Animal class]]; 
    BOOL isEqual1 = [Animal isKindOfClass:[Animal class]]; 
    BOOL isEqual2 = [NSObject isKindOfClass:[NSObject class]]; 
    
    BOOL isEqual3 = [p isMemberOfClass:[Animal class]]; 
    BOOL isEqual4 = [Animal isMemberOfClass:[Animal class]]; 
    BOOL isEqual5 = [NSObject isMemberOfClass:[NSObject class]]; 
    
    
    BOOL isEqual6 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
    BOOL isEqual7 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
    BOOL isEqual8 = [(id)[Dog class] isKindOfClass:[Dog class]]; 
    BOOL isEqual9 = [(id)[Dog class] isMemberOfClass:[Dog class]];
    
NSLog(@"%d__%d_%d_%d__%d_%d_%d__%d_%d_",isEqual,isEqual1,isEqual2,isEqual3,isEqual4,isEqual5,isEqual6,isEqual7,isEqual8,isEqual9);
}

@end

下面公布答案,答对的就撤了吧不要在这里浪费时间了,没答出来的那就跟着我一起一探究竟吧😁😀😃

1__0_1_1__0_0_1__0_0_

先打开objc来看看
+ isMemberOfClass,
- isMemberOfClass,
+ isKindOfClass,
- isKindOfClass
+ (Class)class
- (Class)class

的实现,这些方法都是成对出现的,分别是对象方法和类方法。

分别解释一下各个方法,注意区分区别:

1. isMemberOfClass 方法


     先看+方法
    + (BOOL)isMemberOfClass:(Class)cls {
        return object_getClass((id)self) == cls;
    }
    
    `object_getClass`方法的实现如下,其实就是取isa
    
    Class object_getClass(id obj) {
          if (obj) return obj->getIsa();
          else return Nil;
    }
    
    再看-方法
    
    - (BOOL)isMemberOfClass:(Class)cls {
        return [self class] == cls;
    }
    
    `- (Class)class`的实现如下,实际上也是取isa
    
    - (Class)class {
        return object_getClass(self);
    }

2. isKindOfClass 方法

    先看+方法,通过`object_getClass`方法取得isa,然后和cls对比,相等的话就返回YES,否则会寻找self的isa的父类,如果相等返回YES,否则返回NO.
    
    + (BOOL)isKindOfClass:(Class)cls {
            for (Class tcls = object_getClass((id)self); tcls; tcls = tcls- 
            >superclass) {
                if (tcls == cls) return YES;
            }
          return NO;
    }
    
   在看-方法,和+方法一样
    
    - (BOOL)isKindOfClass:(Class)cls {
            for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
                if (tcls == cls) return YES;
            }
            return NO;
     }

3. class 方法

 先看+方法 返回自身
    + (Class)class {
        return self;
    }

    再看-方法 返回self的isa
    - (Class)class {
        return object_getClass(self);
    }

    注意这里的区别

   

上面提到了isa,那么isa到底是个什么的东西呢 ?

直接xcode搜索NSObject可以看到

    @interface NSObject <NSObject> {
        Class isa  OBJC_ISA_AVAILABILITY;
    }

再点进去看


/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

可以得出结论

  1. Class就是指向objc_class结构体的指针;
  2. id就是指向objc_object结构体的指针;

由类和对象的定义,我们可以看出,其成员变量中都含有isa指针,isa指向的是一个类,其指向该对象所属的类。我们可以把isa当作是一个对象的标志,因此类也是一个对象,我们称之为类对象,其isa指针,指向该类对象所属的类,我们称之为元类(metaClass)

isa指向的类可以通过【object class】 来获取,但是如果是类对象的话通过【class】来获取的话是本身而不是元类,这取决于上面提到的class的实现。我们可以通过object_getClass()来获取isa,适用于实例对象和类对象。

Animal *animal = [[Animal alloc] init];
    Dog *dog = [[Dog alloc] init];
    
    NSLog(@"对象 dog --> isa 指向的地址是 %p",[dog class]);
    NSLog(@"Dog --> isa 指向的地址是 %p",object_getClass([Dog class]));
    NSLog(@"Dog --> isa --> isa 指向的地址是 %p",object_getClass(object_getClass([Dog class])));
    NSLog(@"Dog --> isa --> superclass 的地址是 %p",[object_getClass([Dog class]) superclass]);
    NSLog(@"dog --> superclass 的地址 %p",[dog superclass]);
    
    NSLog(@"============================");
    
    
    NSLog(@"对象 animal --> isa 指向地址是 %p",[animal class]);
    NSLog(@"Animal --> isa 指向地址是 %p",object_getClass([Animal class]));
    NSLog(@"Animal --> isa --> isa 指向的地址是 %p",object_getClass(object_getClass([Animal class])));
    NSLog(@"Animal --> isa --> superclass  的地址是 %p",[object_getClass([Animal class]) superclass]);
    NSLog(@"animal --> superclass 的地址 %p",[animal superclass]);

    
    NSLog(@"============================");
    
    
    NSLog(@"NSObject 的地址 %p",[NSObject class]);
    NSLog(@"NSObject --> isa 的地址是 %p",object_getClass([NSObject class]));
    NSLog(@"NSObject --> isa --> isa 的地址是 %p",object_getClass(object_getClass([NSObject class])));
    NSLog(@"NSObject --> isa --> superclass 的地址是 %p",[object_getClass([NSObject class]) superclass]);
    
    NSLog(@"NSObject --> superclass 的地址 %p",[NSObject superclass]);

打印结果


对象 dog --> isa 指向的地址是 0x1097e37c8
Dog --> isa 指向的地址是 0x1097e37a0
Dog --> isa --> isa 指向的地址是 0x10c6eae38
Dog --> isa --> superclass 的地址是 0x1097e3750
dog --> superclass 的地址 0x1097e3778

============================

对象 animal --> isa 指向地址是 0x1097e3778
Animal --> isa 指向地址是 0x1097e3750
Animal --> isa --> isa 指向的地址是 0x10c6eae38
Animal --> isa --> superclass  的地址是 0x10c6eae38
animal --> superclass 的地址 0x10c6eae88

============================

NSObject 的地址 0x10c6eae88
NSObject --> isa 的地址是 0x10c6eae38
NSObject --> isa --> isa 的地址是 0x10c6eae38
NSObject --> isa --> superclass 的地址是 0x10c6eae88
NSObject --> superclass 的地址 0x0

可以得出下面一张图

362FFD36-BE20-48E0-9019-92A371200071.png

由打印的结果以及上面的图可以得出以下结论:

  1. 实例对象的isa指向对象所属的类, 也叫类对象;
  2. 类对象的isa指向的是类对象所属的类,也就是元类对象;
  3. 元类对象的isa指向元类对象所属的类,也就是根元类对象;
  4. 根元类的isa指向本身。

好了有了上面的理解,我们再来一一解答之前的题目。

  • BOOL isEqual = [p isKindOfClass:[Animal class]];

1. 由于调用的是`- isKindOfClass`方法,所以【p isKindOfClass:】是取出p的isa,由于对象的isa指向的所属的类,也就是Animal类 ==> 【类对象】;
2. [Animal class]调用的是`+class`方法,返回是本身,也就是Animal类 ==> 【类对象】,所以isEqual == YES.

  • BOOL isEqual1 = [Animal isKindOfClass:[Animal class]];
1. [Animal isKindOfClass],结合`+isKindOfClass`的定义,取得是Animal的isa,所以是Animl的元类 ==> 【元类对象】;
2. [Animal class]取的是Animal类 ==>  【类对象】,所以isEqual1 == NO;
  • BOOL isEqual2 = [NSObject isKindOfClass:[NSObject class]];
1. [NSObject class]取的是类NSObject ==> 【类对象】;
2. [NSObject isKindOfClass]取得是NSObject的isa也就是NSObject的元类 ==> 【元类对象】,此时为NO;
3. 由`isKindOfClass`的定义会去寻找NSObject的元类的父类,也就是NSObject,正好等于NSObject 所以isEqual2 == YES.

  • BOOL isEqual3 = [p isMemberOfClass:[Animal class]];
1. [Animal class] - > Animal ==> 【类对象】;
2. [p isMemberOfClass] -> Animal ==> 【类对象】所以 isEqual3 == YES
  • BOOL isEqual4 = [Animal isMemberOfClass:[Animal class]];
1. [Animal class] - > Animal ==>  【类对象】;
2. [Animal isMemberOfClass] -> Animal 的元类  ==>  【元类对象】 所以isEqual4 == NO
  • BOOL isEqual5 = [NSObject isMemberOfClass:[NSObject class]];
1. [NSObject class] - > NSObject ==>  【类对象】;
2. [NSObject isMemberOfClass:] - >  NSObject的元类 ==> 【元类对象】 所以 isEqual5 == NO
  • BOOL isEqual6 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
1. [NSObject class] - > NSObject ==> 【类对象】;
2. (id)[NSObject class] - >   NSObject ==>  【类对象】;
3. [(id)[NSObject class] isKindOfClass] - > NSObject的元类 ==> 【元类对象】 不相等;
4.  NSObject的元类的父类 ->  NSObject ==> 【类对象】 所以 isEqual6 == YES
  • BOOL isEqual7 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
1. [NSObject class] - > NSObject ==> 【类对象】;
2. (id)[NSObject class] - >   NSObject ==> 【类对象】;
3. [(id)[NSObject class] isMemberOfClass] - > NSObject的元类 ==> 【元类对象】 不相等 所以 isEqual7 == NO;
  • BOOL isEqual8 = [(id)[Dog class] isKindOfClass:[Dog class]];
1. [Dog class] - > Dog ==> 【Dog类对象】
2. (id)[Dog class] - > Dog ==>  【Dog类对象】
3. [(id)[Dog class] isKindOfClass] - > Dog 的元类  ==> 【Dog元类对象】不相等;
4. Dog 的元类 的父类 ==> 【Animal 元类对象的父类】  ===>  不等于Dog类对象;
5. Animal的元类的父类的父类 -> 根元类 还是不等于 Dog类对象;
6. 根元类的父类 - > NSObject 不等于Dog对象  
7. NSObject的父类  - > nil  所以isEqual8 == NO。

  • BOOL isEqual9 = [(id)[Dog class] isMemberOfClass:[Dog class]];
1. [Dog class] - > Dog  ==>  【类对象】
2. (id)[Dog class] - > Dog ==>  【类对象】
3. [(id)[Dog class] isMemberOfClass] -> Dog 的元类 ==>  【元类对象】 不相等 所以isEqual9 == NO;

相信到这里大家应该有个很好的认识了。

参考:
http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容