iOS底层系列10 -- 类的结构分析

2021-02-10  本文已影响0人  YanZi_33

元类

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //实例对象
        NSObject *obj1 = [[NSObject alloc]init];
        NSObject *obj2 = [[NSObject alloc]init];
        NSLog(@"实例对象 -- %p -- %p",obj1,obj2);
        
        //类对象
        Class objClass1 = [obj1 class];
        Class objClass2 = [obj2 class];
        Class objClass3 = object_getClass(obj1);
        Class objClass4 = object_getClass(obj2);
        Class objClass5 = [NSObject class];
        NSLog(@"类对象 -- %p -- %p -- %p -- %p -- %p",objClass1,objClass2,objClass3,objClass4,objClass5);
        
        //元类对象
        Class metaClass = object_getClass(objClass1);
        NSLog(@"元类对象 -- %p",metaClass);

        //判断类 是否是元类对象
        bool isMetaClass = class_isMetaClass(metaClass);
        NSLog(@"isMetaClass = %d",isMetaClass);
    }
    return 0;
}
Snip20210624_11.png Snip20210210_137.png Snip20210210_138.png

如何在LLDB调试控制台获取实例对象person的类对象YYPerson的内存地址?

isa指针的指向

由上面的内容我们知道实例对象的isa指向类对象类对象的isa指向元类对象,那元类对象的isa指向哪里?会这样没有终点的一直指向下去么?

Snip20210210_140.png

通过类Class所创建的实例对象在内存中可以成千上万,那么类对象在内存中占几份?

#import <Foundation/Foundation.h>
#import "YYPerson.h"
#import "YYStudent.h"
#import <objc/runtime.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        
        Class class1 = [YYPerson class];
        Class class2 = [YYPerson alloc].class;
        Class class3 = object_getClass(person);
        NSLog(@"\nclass1 = %p\nclass2 = %p\nclass3 = %p", class1, class2, class3);
    }
    return 0;
}
Snip20210210_142.png

引用官方一张 关于 isa走向 与 类继承关系图

Snip20210210_143.png
isa走向(虚线部分)
类的继承superClass的走向(实线部分)
Snip20210213_5.png

类的结构

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() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }

    ......
}
计算cache成员的内存大小
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
    
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
#else
#error Unknown cache mask storage type.
#endif
    
#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;
};
探索bits成员
@interface YYPerson : NSObject

@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger weight;

- (void)walk;
- (void)eat;

+ (void)sing;

@end
Snip20210219_2.png
进入class_rw_t结构体
    const method_array_t methods() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
        }
    }

    const property_array_t properties() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>()->baseProperties};
        }
    }

    const protocol_array_t protocols() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
        }
    }
Snip20210219_3.png Snip20210219_4.png Snip20210219_5.png
    const class_ro_t * ro() const {
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];

    _objc_swiftMetadataInitializer swiftMetadataInitializer() const {
        if (flags & RO_HAS_SWIFT_INITIALIZER) {
            return _swiftMetadataInitializer_NEVER_USE[0];
        } else {
            return nil;
        }
    }

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
    ......
};
Snip20210219_8.png Snip20210219_9.png Snip20210219_10.png
探索类方法的存储位置
Snip20210219_11.png Snip20210219_12.png

通过MJClassInfo.h查看类对象的数据结构

#import <Foundation/Foundation.h>

#ifndef MJClassInfo_h
#define MJClassInfo_h

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
# endif

#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;

struct bucket_t {
    cache_key_t _key;
    IMP _imp;
};

struct cache_t {
    bucket_t *_buckets;
    mask_t _mask;
    mask_t _occupied;
};

struct entsize_list_tt {
    uint32_t entsizeAndFlags;
    uint32_t count;
};

struct method_t {
    SEL name;
    const char *types;
    IMP imp;
};

struct method_list_t : entsize_list_tt {
    method_t first;
};

struct ivar_t {
    int32_t *offset;
    const char *name;
    const char *type;
    uint32_t alignment_raw;
    uint32_t size;
};

struct ivar_list_t : entsize_list_tt {
    ivar_t first;
};

struct property_t {
    const char *name;
    const char *attributes;
};

struct property_list_t : entsize_list_tt {
    property_t first;
};

struct chained_property_list {
    chained_property_list *next;
    uint32_t count;
    property_t list[0];
};

typedef uintptr_t protocol_ref_t;
struct protocol_list_t {
    uintptr_t count;
    protocol_ref_t list[0];
};

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;  // instance对象占用的内存空间
#ifdef __LP64__
    uint32_t reserved;
#endif
    const uint8_t * ivarLayout;
    const char * name;  // 类名
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;  // 成员变量列表
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
};

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    method_list_t * methods;    // 方法列表
    property_list_t *properties;    // 属性列表
    const protocol_list_t * protocols;  // 协议列表
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
};

#define FAST_DATA_MASK          0x00007ffffffffff8UL
struct class_data_bits_t {
    uintptr_t bits;
public:
    class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
};

/* OC对象 */
struct mj_objc_object {
    void *isa;
};

/* 类对象 */
struct mj_objc_class : mj_objc_object {
    Class superclass;
    cache_t cache;
    class_data_bits_t bits;
public:
    class_rw_t* data() {
        return bits.data();
    }
    
    mj_objc_class* metaClass() {
        return (mj_objc_class *)((long long)isa & ISA_MASK);
    }
};

#endif /* MJClassInfo_h */
#import <Foundation/Foundation.h>
#import "YYPerson.h"
#import <objc/runtime.h>
#import <malloc/malloc.h>
#import "MJClassInfo.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        mj_objc_class *personClass = (__bridge mj_objc_class *)([YYPerson class]);
        class_rw_t *personClassData = personClass->data();
        class_rw_t *personMetaClassData = personClass->metaClass()->data();
        
    }
    return 0;
}
Snip20210625_14.png

常见API

@interface YYPerson : NSObject

@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger weight;

- (void)walk;
- (void)eat;

+ (void)sing;

@end
class_getInstanceMethod(Class cls, SEL sel)
void YYClass_getInstanceMethod(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(walk));
    Method method2 = class_getInstanceMethod(metaClass, @selector(walk));

    Method method3 = class_getInstanceMethod(pClass, @selector(sing));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sing));
    
    NSLog(@"%s - %p - %p - %p - %p",__func__,method1,method2,method3,method4);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        person.weight = 130;

        Class cls = object_getClass(person);
        YYClass_getInstanceMethod(cls);
    }
    return 0;
}
class_getClassMethod(Class cls, SEL sel)
Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}
Class getMeta() {
    if (isMetaClass()) return (Class)this;
    else return this->ISA();
}
void YYclass_getClassMethod(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getClassMethod(pClass, @selector(walk));
    Method method2 = class_getClassMethod(metaClass, @selector(walk));
    Method method3 = class_getClassMethod(pClass, @selector(sing));
    Method method4 = class_getClassMethod(metaClass, @selector(sing));
    
    NSLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        person.weight = 130;

        Class cls = object_getClass(person);
        YYclass_getClassMethod(cls);
        
    }
    return 0;
}
class_getMethodImplementation(Class cls, SEL sel)
IMP class_getMethodImplementation(Class cls, SEL sel)
{
    IMP imp;

    if (!cls  ||  !sel) return nil;

    imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);

    // Translate forwarding function to C-callable external version
    if (!imp) {
        return _objc_msgForward;
    }

    return imp;
}
void YYClass_getMethodImplementation(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);

    IMP imp1 = class_getMethodImplementation(pClass, @selector(walk));
    IMP imp2 = class_getMethodImplementation(metaClass, @selector(walk));

    IMP imp3 = class_getMethodImplementation(pClass, @selector(sing));
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(sing));

    NSLog(@"%p - %p - %p - %p",imp1,imp2,imp3,imp4);
    NSLog(@"%s",__func__);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        person.weight = 130;

        Class cls = object_getClass(person);
        YYClass_getMethodImplementation(cls);
    }
    return 0;
}
- (BOOL)isKindOfClass:(Class)cls与+ (BOOL)isKindOfClass:(Class)cls
- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        person.weight = 130;
        
        BOOL re1 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
        BOOL re2 = [(id)[YYPerson alloc] isKindOfClass:[YYPerson class]];
        BOOL re3 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL re4 = [(id)[YYPerson class] isKindOfClass:[YYPerson class]];
    }
    return 0;
}
Snip20210220_16.png
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    Class cls = obj->getIsa();
    if (fastpath(!cls->hasCustomCore())) {
        for (Class tcls = cls; tcls; tcls = tcls->superclass) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
- (BOOL)isMemberOfClass:(Class)cls与+ (BOOL)isMemberOfClass:(Class)cls
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YYPerson *person = [[YYPerson alloc]init];
        person.name = @"liyanyan";
        person.weight = 130;
        
        BOOL re5 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
        BOOL re6 = [(id)[YYPerson alloc] isMemberOfClass:[YYPerson class]];
        BOOL re7 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL re8 = [(id)[YYPerson class] isMemberOfClass:[YYPerson class]];
    }
    return 0;
}

如何获取Class对象

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //实例对象
        NSObject *obj1 = [[NSObject alloc]init];
        NSObject *obj2 = [[NSObject alloc]init];
        NSLog(@"实例对象 -- %p -- %p",obj1,obj2);
        
        //类对象
        Class objClass1 = [obj1 class];
        Class objClass2 = [obj2 class];
        Class objClass3 = [NSObject class];
        Class objClass4 = object_getClass(obj1);
        Class objClass5 = objc_getClass("NSObject");
        Class objClass6 = object_getClass(objClass1);
        
        NSLog(@"class对象 -- %p -- %p -- %p -- %p -- %p -- %p",objClass1,objClass2,objClass3,objClass4,objClass5,objClass6);
        NSLog(@"class对象 -- %p",objClass6);
    }
    return 0;
}
Snip20210624_12.png
上一篇 下一篇

猜你喜欢

热点阅读