包罗万象的runtime(一):对象&类&元类

2018-06-02  本文已影响5人  ElaineYin

苹果官方维护的objc源代码

我们常说OC是一种面向对象的语言,那么
什么是对象?

:对同一类事物的高度抽象。类定义了这一类的属性以及行为准则(方法)。
对象:类的一个实例,是一个具体的事物。

1. runtime中的类和对象

typedef struct objc_class *Class;
typedef struct objc_object *id;

简单从定义来看:Class是一个objc_class结构类型的指针,id(任意对象)是一个objc_object结构类型的指针
再来看下这两个结构体objc_classobjc_object

/// objc_class
struct objc_class {
    Class isa;
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list *methodLists;
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
} ;
/// objc_object
struct objc_object {
    Class isa;
};

objc_class和objc_object都有一个isa指针,我们知道实例的isa指针指向实例所属的类,即objc_object中的isa指针指向了objc_object所属的类objc_class,那么
objc_class中的isa指针指向哪里呢

2. 元类 MetaClass

先看结论

每一个类本质上都是一个对象,类其实是元类(meteClass)的实例。类通过类的isa指针指向元类。所有的元类最终继承一个根元类,根元类isa指针指向本身,形成一个封闭的内循环。

看到这里我又疑惑了,实例的isa指向它所属的类,类的isa指向它的元类,类的元类是什么,是它所继承的父类吗,那么类的isa(元类)和super_class(父类)是不是有关系呢?
还是要来段代码测试一下:

Class class1 = [[NSString alloc] init].class;
Class class = [NSString class];
Class superClass = [NSString superclass];
NSLog(@"%@:%p",NSStringFromClass(class1), class1);
NSLog(@"%@:%p",NSStringFromClass(class), class);
NSLog(@"%@:%p",NSStringFromClass(superClass), superClass);
//输出结果
2018-06-02 08:17:46.802684+0800 RuntimeDemo[1129:82727] __NSCFConstantString:0x108679fe0
2018-06-02 08:17:46.802851+0800 RuntimeDemo[1129:82727] NSString:0x107abad68
2018-06-02 08:17:46.802989+0800 RuntimeDemo[1129:82727] NSObject:0x1080feea8

测试发现,NSString的元类([NSString class])并不是我以为的NSObject,而是NSString,那么实例的isa指针和类的isa指针指向到底哪里不一样呢?还是code一下看看吧
先写个方法输出Class的详细信息

- (void)getInfoFromClass:(Class)cls {
    /// class_getName 获取类name
    NSLog(@"%s:%p",class_getName(cls), cls);
    /// class_isMetaClass用于判断Class对象是否为元类,
    BOOL isMeta = class_isMetaClass(cls);
    NSLog(@"%@",isMeta?@"是元类":@"不是元类");
    // 成员变量
    unsigned int outCount = 0;
    NSLog(@"成员变量 class_copyIvarList:");
    Ivar *ivars = class_copyIvarList(cls, &outCount);
    for (int i = 0; i < outCount; i++) {
        Ivar ivar = ivars[i];
        NSLog(@"%s",ivar_getName(ivar));
    }
    free(ivars);
    
    // 属性操作
    NSLog(@"属性 class_copyPropertyList:");
    objc_property_t * properties = class_copyPropertyList(cls, &outCount);
    for (int i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSLog(@"%s", property_getName(property));
    }
    free(properties);
    
    // 方法操作
    NSLog(@"方法 class_copyMethodList:");
    Method *methods = class_copyMethodList(cls, &outCount);
    for (int i = 0; i < outCount; i++) {
        Method method = methods[i];
        SEL sel = method_getName(method);
        NSLog(@"%@",NSStringFromSelector(sel));
    }
    free(methods);
}

再自定义个Person类(这里为什么不用系统的类呢,因为系统的类方法太多了,输出那么多影响观察)

#pragma mark - 定义一个类Person
@interface Person : NSObject

+ (void)staticDescription;

- (void)instanceDescription;

@end

@implementation Person
+ (void)staticDescription { }

- (void)instanceDescription { }
@end

OK,定义了一个类Person,Person包含一个类方法一个实例方法,打印一下看看

Person *person = [[Person alloc] init];
/// object_getClass用于获取对象的isa指针指向的对象。
[self getInfoFromClass:object_getClass(person)];
[self getInfoFromClass:object_getClass(Person.class)];
/// 输出结果
2018-06-02 09:32:32.473784+0800 RuntimeDemo[2398:280748] Person:0x109bf7010
2018-06-02 09:32:32.473922+0800 RuntimeDemo[2398:280748] 不是元类
2018-06-02 09:32:32.474260+0800 RuntimeDemo[2398:280748] 方法 class_copyMethodList:
2018-06-02 09:32:32.474382+0800 RuntimeDemo[2398:280748] instanceDescription
2018-06-02 09:32:32.474484+0800 RuntimeDemo[2398:280748] Person:0x109bf6fe8
2018-06-02 09:32:32.474635+0800 RuntimeDemo[2398:280748] 是元类
2018-06-02 09:32:32.474960+0800 RuntimeDemo[2398:280748] 方法 class_copyMethodList:
2018-06-02 09:32:32.475084+0800 RuntimeDemo[2398:280748] staticDescription

看到了吧,实例的isa指针指向它所属的类,类的isa指针指向的是类对象的元。类对象存的是关于实例对象的信息(变量,实例方法等),而元类对象(metaclass object)中存储的是关于类的信息(类的版本,名字,类方法等)。

所以类也是对象,是元类的对象

类对象和实例对象的区别:尽管类对象保留了一个类实例的原型,但它并不是实例本身。它没有自己的实例变量,也不能执行那些类的实例的方法(只有实例对象才可以执行实例方法)。然而,类的定义能包含那些特意为类对象准备的方法–类方法( 而不是的实例方法)。类对象从父类那里继承类方法,就像实例从父类那里继承实例方法一样。

来看下说明图:


image.png

参考链接:
https://www.jianshu.com/p/41735c66dccb
http://justsee.iteye.com/blog/2163905
http://www.zhimengzhe.com/IOSkaifa/253119.html

上一篇 下一篇

猜你喜欢

热点阅读