先來做幾道題目,做的出來的就不要往下看了么库。
@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
的實現(xiàn)棍现,這些方法都是成對出現(xiàn)的调煎,分別是對象方法和類方法。
分別解釋一下各個方法轴咱,注意區(qū)分區(qū)別:
1. isMemberOfClass 方法
先看+方法
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
`object_getClass`方法的實現(xiàn)如下汛蝙,其實就是取isa
Class object_getClass(id obj) {
if (obj) return obj->getIsa();
else return Nil;
}
再看-方法
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
`- (Class)class`的實現(xiàn)如下,實際上也是取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);
}
注意這里的區(qū)別
上面提到了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;
可以得出結(jié)論
-
Class
就是指向objc_class
結(jié)構(gòu)體的指針需了; -
id
就是指向objc_object
結(jié)構(gòu)體的指針;
由類和對象的定義般甲,我們可以看出肋乍,其成員變量中都含有isa指針,isa指向的是一個類敷存,其指向該對象所屬的類墓造。我們可以把isa當(dāng)作是一個對象的標(biāo)志,因此類也是一個對象锚烦,我們稱之為類對象觅闽,其isa指針,指向該類對象所屬的類涮俄,我們稱之為元類(metaClass)
isa指向的類可以通過【object class】 來獲取蛉拙,但是如果是類對象的話通過【class】來獲取的話是本身而不是元類,這取決于上面提到的class的實現(xiàn)彻亲。我們可以通過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]);
打印結(jié)果
對象 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
可以得出下面一張圖
由打印的結(jié)果以及上面的圖可以得出以下結(jié)論:
- 實例對象的isa指向?qū)ο笏鶎俚念? 也叫類對象苞尝;
- 類對象的isa指向的是類對象所屬的類硫惕,也就是元類對象;
- 元類對象的isa指向元類對象所屬的類野来,也就是根元類對象恼除;
- 根元類的isa指向本身。
好了有了上面的理解曼氛,我們再來一一解答之前的題目豁辉。
- BOOL isEqual = [p isKindOfClass:[Animal class]];
1. 由于調(diào)用的是`- isKindOfClass`方法,所以【p isKindOfClass:】是取出p的isa舀患,由于對象的isa指向的所屬的類徽级,也就是Animal類 ==> 【類對象】;
2. [Animal class]調(diào)用的是`+class`方法聊浅,返回是本身餐抢,也就是Animal類 ==> 【類對象】现使,所以isEqual == YES.
- BOOL isEqual1 = [Animal isKindOfClass:[Animal class]];
1. [Animal isKindOfClass],結(jié)合`+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召嘶;
相信到這里大家應(yīng)該有個很好的認(rèn)識了父晶。
參考:
http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html