iOS底层原理总结 - 探寻OC对象的本质

2019-11-17  本文已影响0人  爱吃兔兔的胡萝卜吖

iOS底层原理总结 - 探寻OC对象的本质

对小码哥底层班视频学习的总结与记录。

面试题:一个NSObject对象占用多少内存?

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *objc = [[NSObject alloc] init];
        
        NSLog(@"Hello, World!");
    }
    return 0;
}
clang -rewrite-objc main.m -o main.cpp // 这种方式没有指定架构例如arm64架构 其中cpp代表(c plus plus)
生成 main.cpp
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp 
//生成 main-arm64.cpp
//xcrun是xcode的一个工具,xc是xcode的简称
//iphoneos是指定平台,上面一句是在iphone上面的
//-arch 后面是架构,例如:模拟器(i386),32bit(armv7),64bit(arm63)
//  OC源文件  -o  输出的CPP文件
struct NSObject_IMPL {
    Class isa;
};
// 查看Class本质,command点击进入class
typedef struct objc_class *Class;
我们发现Class其实就是一个指针,对象底层实现其实就是这个样子。
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
@end

@interface NSObject {
    Class isa ;
}
@end
struct NSObject_IMPL {
    Class isa;
};
NSObject *objc = [[NSObject alloc] init];
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
//这个函数的解释是返回一个类的实例对象的大小
//获得NSObject实例对象的成员变量所占用的大小 >> 8
NSLog(@"%zd", malloc_size((__bridge const void *)obj));
//获得obj指针所指向内存的大小 >> 16
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
// Class's ivar size rounded up to a pointer-size boundary.
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }

id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
    id obj;

#if __OBJC2__
    // allocWithZone under __OBJC2__ ignores the zone parameter
    (void)zone;
    obj = class_createInstance(cls, 0);
#else
    if (!zone) {
        obj = class_createInstance(cls, 0);
    }
    else {
        obj = class_createInstanceFromZone(cls, 0, zone);
    }
#endif

    if (slowpath(!obj)) obj = callBadAllocHandler(cls);
    return obj;
}
id 
class_createInstance(Class cls, size_t extraBytes)
{
    return _class_createInstanceFromZone(cls, extraBytes, nil);
}
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
    if (!cls) return nil;

    assert(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size);
        if (!obj) return nil;
        obj->initInstanceIsa(cls, hasCxxDtor);
    } 
    else {
        if (zone) {
            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (!obj) return nil;

        // Use raw pointer isa on the assumption that they might be 
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (cxxConstruct && hasCxxCtor) {
        obj = _objc_constructOrFree(obj, cls);
    }

    return obj;
}
size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
    

回答面试题:

自定义类的实例对象内存分配情况

面试题:在64bit环境下,自定类的实例对象占用多少内存呢?

@interface Student : NSObject{
    
    @public
    int _no;
    int _age;
}
@end
@implementation Student

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Student *stu = [[Student alloc] init];
        stu -> _no = 4;
        stu -> _age = 5;
        
        NSLog(@"%@",stu);
    }
    return 0;
}
@end
struct Student_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _no;
    int _age;
};
struct NSObject_IMPL {
    Class isa;
};
struct Student_IMPL {
    Class *isa;
    int _no;
    int _age;
};
Student *stu = [[Student alloc] init];
stu -> _no = 4;
stu -> _age = 5;
struct Student_IMPL {
    Class isa;
    int _no;
    int _age;
};

@interface Student : NSObject
{
    @public
    int _no;
    int _age;
}
@end

@implementation Student

int main(int argc, const char * argv[]) {
    @autoreleasepool {
            // 强制转化
            struct Student_IMPL *stuImpl = (__bridge struct Student_IMPL *)stu;
            NSLog(@"_no = %d, _age = %d", stuImpl->_no, stuImpl->_age); // 打印出 _no = 4, _age = 5
    }
    return 0;
}
NSLog(@"NSObject = %zd",class_getInstanceSize([NSObject class]));
//类对象实际需要内存大小
 NSLog(@"Student = %zd", class_getInstanceSize([Student class]));
//系统分配
 NSLog(@"Student = %zd", malloc_size((__bridge const void *)stu));
OC对象本身占用内存大小.png

窥探内存结构

实时查看内存数据

方式二:通过lldb指令xcode自带的调试器
memory read 0x10074c450
// 简写  x 0x10074c450

// 增加读取条件
// memory read/数量格式字节数  内存地址
// 简写 x/数量格式字节数  内存地址
// 格式 x是16进制,f是浮点,d是10进制
// 字节大小   b:byte 1字节,h:half word 2字节,w:word 4字节,g:giant word 8字节

示例:x/4xw    //   /后面表示如何读取数据 w表示4个字节4个字节读取,x表示以16进制的方式读取数据,4则表示读取4次
memory write 0x100400c68 6
将_no的值改为了6
lldb读取内存.png

更复杂的继承关系(继承关系的类的类的对象内存分配情况)

面试题:在64bit环境下,继承关系的子父类占用内存情况如何呢?

/* Person */
@interface Person : NSObject
{
    int _age;
}
@end

@implementation Person
@end

/* Student */
@interface Student : Person
{
    int _no;
}
@end

@implementation Student
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NSLog(@"%zd  %zd",
              class_getInstanceSize([Person class]),
              class_getInstanceSize([Student class])
              );
    }
    return 0;
}

//打印结果如下:
Interview01-OC对象的本质[2872:67593] stu - 16
Interview01-OC对象的本质[2872:67593] person - 16
struct NSObject_IMPL {
    Class isa;//8
};

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 8
    int _age; // 4
}; // 16 内存对齐:结构体的大小必须是最大成员大小的倍数

struct Student_IMPL {
    struct Person_IMPL Person_IVARS; // 16
    int _no; // 4
}; // 16

系统给对象分配内存时会遵循内存对齐:结构体的大小必须是最大成员大小的倍原则,也就说Person_IMPL结构体中的成员变量(isa跟_age)实际需要12字节空间,但是系统根据原则确分配了16字节,所以结果是16字节。
而** Student_IMPL怎么又成了16字节呢,上面说了系统给Person_IMPL分配了16字节,实际占用12字节,还留有4字节空余,恰好放_no**4字节的变量,这样出来的结果就是系统分配16字节恰好够Student_IMPL对象使用。

所以,综上:

补充:

// Person
@interface Person : NSObject
{
    @public
    int _age;
}
@property (nonatomic, assign) int height;
@end

@implementation Person

@end

//Student
@interface Student : Person
{
    int _no;
}
@end

@implementation Student

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"stu - %zd", class_getInstanceSize([Student class]));
        NSLog(@"person - %zd", class_getInstanceSize([Person class]));
       
    }
    return 0;
}
//打印结果如下:
Interview01-OC对象的本质[2872:67593] stu - 24
Interview01-OC对象的本质[2872:67593] person - 16

补充:

@interface MJPerson : NSObject
{
    int _age;
    int _height;
    int _no;
}
@end

@implementation MJPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MJPerson *p = [[MJPerson alloc] init];
        
        NSLog(@"%zd", sizeof(struct MJPerson_IMPL)); // 24
        
        NSLog(@"%zd %zd",
              class_getInstanceSize([MJPerson class]), // 24
              malloc_size((__bridge const void *)(p))); // 32
    }
    return 0;
}
struct MJPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;  //8
    int _age;  //4
    int _height;  //4
    int _no;  //4
}; // 计算结构体大小,本质应该是20,根据上面讲到的原则,内存对齐和是最大内存的倍数,所以是24
struct NSObject_IMPL {
    Class isa;
};
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
    id obj;

#if __OBJC2__
    // allocWithZone under __OBJC2__ ignores the zone parameter
    (void)zone;
    obj = class_createInstance(cls, 0);
#else
    if (!zone) {
        obj = class_createInstance(cls, 0);
    }
    else {
        obj = class_createInstanceFromZone(cls, 0, zone);
    }
#endif

    if (slowpath(!obj)) obj = callBadAllocHandler(cls);
    return obj;
}
obj = class_createInstance(cls, 0);
id 
class_createInstance(Class cls, size_t extraBytes)
{
    return _class_createInstanceFromZone(cls, extraBytes, nil);
}

id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
    if (!cls) return nil;

    assert(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size);
        if (!obj) return nil;
        obj->initInstanceIsa(cls, hasCxxDtor);
    } 
    else {
        if (zone) {
            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (!obj) return nil;

        // Use raw pointer isa on the assumption that they might be 
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (cxxConstruct && hasCxxCtor) {
        obj = _objc_constructOrFree(obj, cls);
    }

    return obj;
}
obj = (id)calloc(1, size);
//知道这个函数传入了一个size,这个size是从
// size_t size = cls->instanceSize(extraBytes);得到的;
size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
    //extraBytes是额外的字节数
    //通过_objc_rootAllocWithZone()函数里面的obj = class_createInstance(cls, 0);可以知道,这个额外的字节数,传入的是0;
// Class's ivar size rounded up to a pointer-size boundary.
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
obj = (id)calloc(1, size);
//相当于
obj = (id)calloc(1, class_getInstanceSize(Class cls));
//所以这个地方的size传入的的确是24
void *
calloc(size_t num_items, size_t size)
{
    void *retval;
    retval = malloc_zone_calloc(default_zone, num_items, size);
    if (retval == NULL) {
        errno = ENOMEM;
    }
    return retval;
}
void *
malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
    void *ptr;
    size_t alloc_size;
    if (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {
        internal_check();
    }
    if (os_mul_overflow(num_items, size, &alloc_size) || alloc_size > MALLOC_ABSOLUTE_MAX_SIZE){
        errno = ENOMEM;
        return NULL;
    }

    ptr = zone->calloc(zone, num_items, size);
    
    if (malloc_logger) {
        malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,
                (uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);
    }
    return ptr;
}
总结
2019-03-15 10:51:36.718391+0800 iOSProject[28310:10739021] ********64位环境********
2019-03-15 10:51:36.718741+0800 iOSProject[28310:10739021] bool size:1
2019-03-15 10:51:36.718817+0800 iOSProject[28310:10739021] BOOL size:1
2019-03-15 10:51:36.718856+0800 iOSProject[28310:10739021] char size:1
2019-03-15 10:51:36.718895+0800 iOSProject[28310:10739021] int8_t size:1
2019-03-15 10:51:36.718928+0800 iOSProject[28310:10739021] unsigned char size:1
2019-03-15 10:51:36.718960+0800 iOSProject[28310:10739021] Boolean size:1
2019-03-15 10:51:36.718993+0800 iOSProject[28310:10739021] short size:2
2019-03-15 10:51:36.719025+0800 iOSProject[28310:10739021] int16_t size:2
2019-03-15 10:51:36.719059+0800 iOSProject[28310:10739021] unsigned short size:2
2019-03-15 10:51:36.719092+0800 iOSProject[28310:10739021] unichar size:2
2019-03-15 10:51:36.719125+0800 iOSProject[28310:10739021] int size:4
2019-03-15 10:51:36.719158+0800 iOSProject[28310:10739021] int32_t size:4
2019-03-15 10:51:36.719190+0800 iOSProject[28310:10739021] unsigned int size:4
2019-03-15 10:51:36.719222+0800 iOSProject[28310:10739021] boolean_t size:4
2019-03-15 10:51:36.719297+0800 iOSProject[28310:10739021] long size:8
2019-03-15 10:51:36.719334+0800 iOSProject[28310:10739021] NSInteger size:8
2019-03-15 10:51:36.719367+0800 iOSProject[28310:10739021] long size:8
2019-03-15 10:51:36.719401+0800 iOSProject[28310:10739021] unsigned long size:8
2019-03-15 10:51:36.719435+0800 iOSProject[28310:10739021] NSUInteger size:8
2019-03-15 10:51:36.719471+0800 iOSProject[28310:10739021] long long size:8
2019-03-15 10:51:36.719503+0800 iOSProject[28310:10739021] double size:8

OC对象的分类

面试题:OC对象都有哪些呢?

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

/* Person */ 
@interface Person : NSObject <NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign) int height;
- (void)personMethod;
+ (void)personClassMethod;
@end

@implementation Person
- (void)personMethod {}
+ (void)personClassMethod {}
@end

/* Student */
@interface Student : Person <NSCoding>
{
    @public
    int _no;
}
@property (nonatomic, assign) int score;
- (void)studentMethod;
+ (void)studentClassMethod;
@end

@implementation Student
- (void)studentMethod {}
+ (void)studentClassMethod {}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {      
        NSObject *object1 = [[NSObject alloc] init];
        NSObject *object2 = [[NSObject alloc] init];

        Student *stu = [[Student alloc] init];
        [Student load];

        Person *p1 = [[Person alloc] init];
        p1->_age = 10;
        [p1 personMethod];
        [Person personClassMethod];
        Person *p2 = [[Person alloc] init];
        p2->_age = 20;
    }
    return 0;
}

Objective-C中的对象,简称OC对象,主要可以分为3种

instance对象(实例对象)

NSObjcet *object1 = [[NSObjcet alloc] init];
NSObjcet *object2 = [[NSObjcet alloc] init];

衍生问题:在上图实例对象中根本没有看到方法,那么实例对象的方法的代码放在什么地方呢?那么类的方法的信息,协议的信息,属性的信息都存放在什么地方呢?

class对象(类对象)

Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = [NSObject class];

// runtime
Class objectClass4 = object_getClass(object1);
Class objectClass5 = object_getClass(object2);
NSLog(@"%p %p %p %p %p", objectClass1, objectClass2, objectClass3, objectClass4, objectClass5);

//内存打印地址如下:
objectClass1 = 0x7fff97528118 objectClass2 = 0x7fff97528118 objectClass3 = 0x7fff97528118 objectClass4 = 0x7fff97528118 objectClass5 = 0x7fff97528118

// 而调用类对象的class方法时得到还是类对象,无论调用多少次都是类对象
Class cls = [[NSObject class] class];
Class objectClass6 = [NSObject class];
NSLog(@"objectClass = %p cls = %p", objectClass6, cls); // 后面两个地址相同,说明多次调用class得到的还是类对象

//打印结果如下:
objectClass = 0x7fff97528118 cls = 0x7fff97528118

class对象在内存中存储的信息主要包括

meta-class对象(元类对象)

//runtime中传入类对象此时得到的就是元类对象
Class objectMetaClass = object_getClass([NSObject class]);
NSLog(@"objectMetaClass = %p",objectMetaClass);

//内存打印地址如下:
objectMetaClass = 0x7fff975280f0


// 而调用类对象的class方法时得到还是类对象,无论调用多少次都是类对象
Class cls = [[NSObject class] class];
Class objectClass3 = [NSObject class];
class_isMetaClass(objectMetaClass) // 判断该对象是否为元类对象
NSLog(@"%p %p %p", objectMetaClass, objectClass3, cls); // 后面两个地址相同,说明多次调用class得到的还是类对象

//检查是否为元类对象
BOOL ismetaclass = class_isMetaClass(objectMetaClass);// 判断该对象是否为元类对象
NSLog(@"objectMetaClass 是否是元类对象 - %ld",ismetaclass);

//打印结果如下:
objectMetaClass 是否是元类对象 - 1

补充
objc_getClass()和object_getClass()的区别;那么[NSObject class]中的class有什么不同呢?
Class objc_getClass(const char *aClassName)
{
    if (!aClassName) return Nil;

    // NO unconnected, YES class handler
    return look_up_class(aClassName, NO, YES);
}
//分析:接收的是类名;其实质就是字符串;

Class 
look_up_class(const char *name, 
              bool includeUnconnected __attribute__((unused)), 
              bool includeClassHandler __attribute__((unused)))
{
    if (!name) return nil;

    Class result;
    bool unrealized;
    {
        rwlock_reader_t lock(runtimeLock);
        result = getClass(name);
        unrealized = result  &&  !result->isRealized();
    }
    if (unrealized) {
        rwlock_writer_t lock(runtimeLock);
        realizeClass(result);
    }
    return result;
}
static Class getClass(const char *name)
{
    runtimeLock.assertLocked();

    // Try name as-is
    Class result = getClass_impl(name);
    if (result) return result;

    // Try Swift-mangled equivalent of the given name.
    if (char *swName = copySwiftV1MangledName(name)) {
        result = getClass_impl(swName);
        free(swName);
        return result;
    }

    return nil;
}
static Class getClass_impl(const char *name)
{
    runtimeLock.assertLocked();

    // allocated in _read_images
    assert(gdb_objc_realized_classes);

    // Try runtime-allocated table
    Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
    if (result) return result;

    // Try table from dyld shared cache
    return getPreoptimizedClass(name);
}
Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    //这句的意思是,如果传进来的是,instance对象,就返回class对象;如果传进来的是,class对象,就返回meta-class对象;如果传进来是meta-class对象,就返回NSObject(基类)的meta-class对象;
    //getIsa()其实就是返回的是isa;
    else return Nil;
}
//分析:接收的是类对象;

面试题:对象的isa指针指向哪里。

[Preson personClassMethod];
//实质就是给这个Preson类发送一个消息
//objc_msgSend([Preson class] @selector(personClassMethod))
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

// MJPerson
@interface MJPerson : NSObject <NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation MJPerson

- (void)test
{
    
}

- (void)personInstanceMethod
{
    
}
+ (void)personClassMethod
{
    
}
- (id)copyWithZone:(NSZone *)zone
{
    return nil;
}
@end

// MJStudent
@interface MJStudent : MJPerson <NSCoding>
{
@public
    int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end

@implementation MJStudent
- (void)test
{
    
}
- (void)studentInstanceMethod
{
    
}
+ (void)studentClassMethod
{
    
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
    return nil;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MJStudent *student = [[MJStudent alloc] init];
        
        
        
        [student test];
        

        [student personInstanceMethod];
        
        [student init];
        
        [MJStudent studentClassMethod];
        
        [MJStudent personClassMethod];
        
        [MJStudent load];
    }
    return 0;
}
MJStudent *student = [[MJStudent alloc]init];
//方法1:调用实例方法
[student studentInstanceMethod];

//方法2:调用类方法
[MJStudent studentClassMethod];
总结
OC对象的superclass指针指向位置

当对象调用其父类对象方法的时候,又是怎么找到父类对象方法的呢?


对象调用父类对象方法图例.png
//方法1:调用父类的实例方法
[student personInstanceMethod];
//方法2:调用父类的类方法
[MJStudent personClassMethod];
总结

如何证明isa指针的指向真的如上面所说?代码求证isa指针指向是否正确;

NSObject *object = [[NSObject alloc] init];//instance对象
Class objectClass = [NSObject class];//类对象 
Class objectMetaClass = object_getClass([NSObject class]);//元类对象
NSLog(@"object - %p objectClass - %p objectMetaClass - %p", object, objectClass, objectMetaClass);

//打印结果如下:
object - 0x10051e0b0    //instance对象内存地址
objectClass - 0x7fff9abb6118 //类对象内存地址
objectMetaClass - 0x7fff9abb60f0  //元类对象内存地址

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

// MJPerson
@interface MJPerson : NSObject <NSCopying>
{
@public
    int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation MJPerson

- (void)test
{
    
}

- (void)personInstanceMethod
{
    
}
+ (void)personClassMethod
{
    
}
- (id)copyWithZone:(NSZone *)zone
{
    return nil;
}
@end

// MJStudent
@interface MJStudent : MJPerson <NSCoding>
{
@public
    int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end

@implementation MJStudent
- (void)test
{
    
}
- (void)studentInstanceMethod
{
    
}
+ (void)studentClassMethod
{
    
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
    return nil;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    
}
@end

struct mj_objc_class {
    Class isa;
    Class superclass;
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        
    MJPerson *person = [[MJPerson alloc] init];
    Class personClass = [MJPerson class];
    NSLog(@"%p %p %p", person, personClass, personMetaClass);

    }
    return 0;
}
typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

struct xx_cc_objc_class{
    Class isa;
};


Class objectClass = [NSObject class];
struct xx_cc_objc_class *objectClass2 = (__bridge struct xx_cc_objc_class *)(objectClass);

补充
Class personClass = [MJPerson class];
Class studentClass = [MJStudent class];

NSLog(@"1111");
struct mj_objc_class {
    Class isa;
    Class superclass;
};

struct mj_objc_class *personClass = (__bridge struct mj_objc_class *)([MJPerson class]);

struct mj_objc_class *studentClass = (__bridge struct mj_objc_class *)([MJStudent class]);

NSLog(@"1111");
验证superclass.png

本文面试题总结

上一篇下一篇

猜你喜欢

热点阅读