美文网首页Objective-C
Playground for Objective-C - 深入理

Playground for Objective-C - 深入理

作者: 山天大畜 | 来源:发表于2017-12-12 21:25 被阅读54次

只要能充分理解上面这张图,就能理解meta class了。

图中实线是 super_class指针,虚线是isa指针。
Root class (class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的superclass指向nil。
每个Class都有一个isa指针指向唯一的Meta class
Root class(meta)的superclass指向Root class(class),也就是NSObject,形成一个回路。
每个Meta class的isa指针都指向Root class (meta)。
object_getClass方法能获取到对象的isa指针

举个例子,我们做以下实验看看输出结果:

@ interface Father : NSObject
@ end
@ interface Son : Father
@ end

Son *son = [Son new];
Father *father = [Father new];


NSLog(@ "[Father class]: %p", [Father class]); //1. 0x10eb1c218
NSLog(@ "[father class]: %p", [father class]); //2. 0x10eb1c218
NSLog(@ "[Son class]: %p", [Son class]); //3. 0x10eb1c240
NSLog(@ "[son class]: %p", [son class]); //4. 0x10eb1c240
NSLog(@ "[son superclass]: %p", [son superclass]);//5. 0x10eb1c218
NSLog(@ "[father superclass]: %p", [father superclass]); //6. 0x11023dea8
NSLog(@ "[NSObject class]: %p", [NSObject class]); //7. 0x11023dea8
NSLog(@ "[NSObject superclass]: %p", [NSObject superclass]); //8. 0x0
NSLog(@ "[son isa]: %p", object_getClass(son)); //9. 0x10eb1c240
NSLog(@ "[[son class] isa]: %p", object_getClass([son class])); //10. 0x10eb1c268
NSLog(@ "[father isa]: %p", object_getClass(father)); //11. 0x10eb1c218
NSLog(@ "[[father class] isa]: %p", object_getClass([father class])); //12. 0x10eb1c1f0
NSLog(@ "[[NSObject class] isa]: %p", object_getClass([NSObject class])); //13. 0x11023de58
NSLog(@ "[[[NSObject class] isa] superclass]: %p", [(id)object_getClass([NSObject class]) superclass]); //14. 0x11023dea8
NSLog(@ "[[[Father class] isa] superclass]: %p", [(id)object_getClass([Father class]) superclass]); //15. 0x11023de58
NSLog(@ "[[[Son class] isa] superclass]: %p", [(id)object_getClass([Son class]) superclass]); //16. 0x10eb1c1f0
NSLog(@ "[[[NSObject class] isa] isa]: %p", object_getClass(object_getClass([NSObject class]))); //17. 0x11023de58
NSLog(@ "[[[father class] isa] isa]: %p", object_getClass(object_getClass([father class]))); //18. 0x11023de58
NSLog(@ "[[[son class] isa] isa]: %p", object_getClass(object_getClass([son class]))); //19. 0x11023de58
    

得出结论:(牢记!

  • [Father class] == [father class]
  • [Son class] == [son class]
  • [son superclass] == [Father class]
  • [NSObject class] == [father superclass]
  • [NSObject superclass] == nil
  • son->isa == [Son class]
  • father->isa == [Father class]
  • [[NSObject class]->isa superclass] == [NSObject class]
  • [[Father class]->isa superclass] == [NSObject class]->isa
  • [[Son class]->isa superclass] == [Father class]->isa
  • [NSObject class]->isa->isa == [NSObject class]->isa
  • [Father class]->isa->isa == [Son class]->isa->isa == [NSObject class]->isa

把这个例子映射到第一幅图能更好的理解以上结论:



概念的说明

在Objective-C中,对象的类是isa指针决定的。isa指针指向对象所属的类。
Objective-C中对象最基本的定义是这样的:

typedef struct objc_object {
    Class isa;
} *id;

任何带有以指针开始并指向类结构的结构都可以被视作objc_object。

Objective-C中对象最重要的特点是你可以发送消息给它们:

[@ "stringValue"
    writeToFile:@ "/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];

这能工作是因为Objective-C对象(这儿是NSCFString)在发送消息时,运行时库会追寻着对象的isa指针得到了对象所属的类(这儿是NSCFString类)。这个类包含了能应用于这个类的所有实例方法和指向超类的指针以便可以找到父类的实例方法。运行时库检查这个类和其超类的方法列表,找到一个匹配这条消息的方法(在上面的代码里,是NSString类的writeToFile:atomically:encoding:error方法)。运行时库基于那个方法调用函数(IMP)。

什么是元类

Objective-C的一个类也是一个对象。这意味着你可以发送消息给一个类。

NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];

在这个示例里,defaultStringEncoding被发送给了NSString类。

因为Objective-C中每个类本身也是一个对象。这意味着类结构必须以一个isa指针开始,从而可以和objc_object在二进制层面兼容,然后这个结构的下一字段必须是一个指向超类的指针(对于基类则为nil)。

typedef struct objc_class *Class;
struct objc_class {
    Class isa;
    Class super_class;
    /* followed by runtime specific details... */
};

这就引出了元类的定义:元类是类对象的类

简单说就是:

  • 当你给对象发送消息时,消息是在寻找这个对象的类的方法列表。
  • 当你给类发消息时,消息是在寻找这个类的元类的方法列表。
    元类是必不可少的,因为它存储了类的类方法。每个类都必须有独一无二的元类,因为每个类都有独一无二的类方法。

元类的类是什么?

元类,就像之前的类一样,它也是一个对象。你也可以调用它的方法。自然的,这就意味着他必须也有一个类。

所有的元类都使用根元类(继承体系中处于顶端的类的元类)作为他们的类。这就意味着所有NSObject的子类(大多数类)的元类都会以NSObject的元类作为他们的类

根据这个规则,所有的元类使用根元类作为他们的类,根元类的元类则就是它自己。也就是说基类的元类的isa指针指向他自己。

类和元类的继承

类用 super_class指针指向了超类,同样的,元类用super_class指向类的super_class的元类。

在这样的继承体系下,所有实例、类以及元类(meta class)都继承自一个基类。

这意味着对于继承于NSObject的所有实例、类和元类,他们可以使用NSObject的所有实例方法,类和元类可以使用NSObject的所有类方法

做一些练习

isKindOfClass 与 isMemberOfClass

来看一道题,猜猜下面代码输出什么?


@ interface Foo : NSObject
@ end
@ implementation Foo
@ end
int main(int argc, const char * argv[]) {
    @ autoreleasepool {
        NSLog(@ "%d", [(id)[NSObject class] isKindOfClass:[NSObject class]]);
        NSLog(@ "%d", [(id)[NSObject class] isMemberOfClass:[NSObject class]]);
        NSLog(@ "%d", [(id)[Foo class] isKindOfClass:[Foo class]]);
        NSLog(@ "%d", [(id)[Foo class] isMemberOfClass:[Foo class]]);
    }
    return 0;
}

提示:isKindOfClass和isMemberOfClass的源码实现如下:

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}
Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

如果你认为第一行的结论是:NSObject isKindOfClass NSObject,显然结果是YES。
那么恭喜你,掉坑里了!

正确的思考应该是这样的:

  • 取得NSObject的isa,这时候NSObject->isa != NSObject
  • 接下来取NSObject->isa的superClass,即NSObject,这下NSObject == NSObject
  • return YES

剩下的几行同理分析,均为NO。

参考引用:
http://ios.jobbole.com/81657/
http://ios.jobbole.com/89209/

相关文章

网友评论

    本文标题:Playground for Objective-C - 深入理

    本文链接:https://www.haomeiwen.com/subject/ufvgixtx.html