iOS-类(NSObject)的结构

1、NSObject

NSObject为全部类的根类,它位于整个类层次的根上,类层次中的全部其它类最终都是从根类继承而来。(万物皆NSObjectbash

2、类的结构

咱们知道全部的类均可以用class接收,因此咱们建立一个类对象app

Person *person = [Person alloc];
Class pClass     = object_getClass(person);
复制代码

查看Class源码:ui

typedef struct objc_class *Class;
复制代码

查看objc_class源码:this

struct objc_class : objc_object {
    // Class ISA; 
    Class superclass; //
    cache_t cache;    // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

	// 下面是一些方法
	class_rw_t *data() { 
        return bits.data();
    }
	…
}
复制代码

objc_class中的Class ISA属性继承自父类 objc_object,查看objc_object源码:atom

struct objc_object {
private:
    isa_t isa;
…
}
复制代码

???、objc_object与NSObject有什么关系呢? 咱们再来看NSObject的源码定义:spa

NSObject的源码定义:
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
复制代码

其实他们是同一个事物的不一样表现形式。objc_object为c结构体写法,而NSObject为OC写法。3d

3、类的属性与方法

咱们为类对象添加成员变量、属性和实例方法、类方法:调试

@interface Person : NSObject{
    NSString *hobby;
}
@property (nonatomic, copy) NSString *nickName;
- (void)sayHello;
+ (void)sayHappy;
@end
复制代码

一、定位源码

首先咱们查看objc_class源码中的方法:code

class_rw_t *data() { 
    return bits.data();
}
复制代码

查看class_rw_t,surprise:orm

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;
    
//———————————重点—————————————
    const class_ro_t *ro;

    method_array_t methods;  
    property_array_t properties;
    protocol_array_t protocols;
//——————————————————————————

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;

#if SUPPORT_INDEXED_ISA
    uint32_t index;
#endif
    …
};

复制代码

因此咱们要找的东西就在这个class_rw_t里面。

二、查当作员变量和属性

接下来咱们开始lldb调试:

咱们须要class_data_bits_t bits的地址:

Class ISA(8个字节)+ Class superclass(8个字节)+ cache_t cache(?)

仍是查看源码:

typedef uint32_t mask_t; // 4

struct cache_t {
    struct bucket_t *_buckets; // 8
    mask_t _mask;  // 4
    mask_t _occupied; // 4
	…
}
复制代码

得出: Class ISA(8个字节)+ Class superclass(8个字节)+ cache_t cache(16个字节),即偏移0x20个字节。

查看它的const class_ro_t *ro参数:

2.1 baseProtocols参数

完美找到它的属性nickName。

2.2 ivars参数

发现ivars里面同时包含了成员变量hobby,以及带下划线的属性_nickName。

2.3 baseMethodList参数

iOS底层会对属性自动添加带下划线的成员变量以及实现它的getter和setter方法

三、查看实例方法

实例方法一样存在于baseMethodList中

四、查看类方法

咱们会发现,在class_data_bits_t里面,是不管如何都找不到类方法的,怎么办呢?咱们只能去它的元类里面查看。定义一个方法:

void testInstanceMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
    
    Method method3 = class_getInstanceMethod(pClass, @selector(sayByeBye));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayByeBye));
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
}

复制代码

打印结果:

0x100002248-0x0-0x0-0x1000021e0

印证了咱们的想法,类方法确实存在于它的元类里面。

相关文章
相关标签/搜索