oc底层原理再总结

1、oc对象的本质是什么

oc本质就是就是结构体, i s a \color{red}{这些结构体都里面包含一个isa指针}
class_getInstanceSize([Student class])。
获取对象占用的内存。
可以用c语言来实现对象原理。
\color{red}{实例的方法并没有放到实例对象里面。 }
oc对象主要可以分为三种:

  • instance对象 (实例对象)
  • objc_object 是这个
    struct Student_IMPL {
    Class isa;
    //根类的实例变量
    //倒数第二层父类的实例变量

    //父类的实例变量
    //类的实例变量
    };
    struct Student_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _no;
    int _age;
    NSString *_name;
    NSString *_school;
    };
  • class 对象 (类对象)
  • objc_class 是这个
    struct object_class *isa;
    struct objc_class {
    struct objc_class isa;//或者叫Class isa;
    const char *_NonNull name;
    long version
    long info
    long instance_size
    struct objc_ivar_list * _NUllable ivars;
    struct oject_method_list * _Nullable * _Nullable methodLists
    struct objc_cache * _Nonnull cache
    struct objc_protocol_list * _Nullable protocols;
    }
    Printing description of ivarList:
    <__NSArrayM 0x12d908690>(
    _number1,
    _number2,
    _name,
    _school
    )
#import <Foundation/Foundation.h>
@interface Earth : NSObject {
    int lang;
    int uage;
}

@property(nonatomic, copy) NSString *country;
@property(nonatomic, copy) NSString *xinyang;

@end

@implementation Earth


@end


@interface Student : Earth {
    @public
    int _no;
    int _age;
}

@property(nonatomic, copy) NSString *name;
@property(nonatomic, copy) NSString *school;

@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

没有继承的代码

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

@property(nonatomic, copy) NSString *name;
@property(nonatomic, copy) NSString *school;

@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

得到的测试数据:

clang获得实例对象里面的数据

struct Earth_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int lang;
int uage;
NSString *_country;
NSString *_xinyang;
};

通过runtime获取到的实例对象里面的数据

struct Student_IMPL {
struct Earth_IMPL Earth_IVARS;
int _no;
int _age;
NSString *_name;
NSString *_school;
};

但是我们发现那个

+(NSArray *)getAllIvars
{
    u_int count;
     Ivar * ivars  = class_copyIvarList([self class], &count);
       NSMutableArray *lvarsArray = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i < count ; i++)
    {
        const char* ivarName = ivar_getName(ivars[i]);
        [propertiesArray addObject: [NSString stringWithUTF8String: ivarName]];
    }
    free(ivars);
    return lvarsArray;
}

获取到的列表只有四个,即

Printing description of ivarList:
<__NSArrayM 0x1013014c0>(
_no,
_age,
_name,
_school
)

总结

  • 测试发现实例变量在实例的结构体和Class结构体里面都有。
  • 实例对面通过结构体包含结构体罗列了从基类到目前类所有的实例变量
  • 但是类对象里面只获取到本类的实例变量

简称:Class isa;

  • meta-class 对象(元类对象)
    这个也是Class isa;

2、instance 对象是什么

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

  • isa指针
  • 成员变量

3、Class对象原理是什么

我们通过class方法或runtime方法得到一个class对象,class对象也就是类对象

扫描二维码关注公众号,回复: 11476197 查看本文章
Class objectClass1 = [object1 class];
Class objectClass3 = [NSObject class];

c l a s s \color{red}{每一个类的内存有且只有一个class对象。 }
class 对象在内存中存储的信息主要包括

  • isa指针
  • superclass指针
  • 类的属性信息,类的成员变量信息
  • 类的对象方法信息(instance method),类的协议信息(protocol)

4、meta-class对象

每个类在内存中有且只有一个meta-class对象。
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括。

  • isa 指针
  • superclass指针
  • 类的类方法的信息(class method)
    meta-class对象和class对象的内存结构是一样的,所以meta-class中也有类的属性信息,类的对象方法信息等成员变量,但其中的值可能是空的

5、isa指针指向哪里

经典的isa指向图

  • 对象的isa指针指向了哪里
    [stu studentMethod]
    (1)、当对象调用实例方法的时候,我们上面讲到,实例方法信息是存储在class类对象中的,那么要想找到实例方法,就必须找到class类对象,就必须找到class类对象,那么此时isa的作用就来了。
    instance的isa指向class,当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用。
    (2)、当类对象调用类方法的时候,同上,类方法是存储在meta-class元类对象中的。那么要找到类方法,就需要找到meta-class元类对象,而class类对象的isa指针就指向元类对象。
    (3)、当对象调用其父类对象方法的时候,又是怎么找到父类对象的方法呢?,此时就需要使用到class类对象的superclass指针。
[stu personMethod]
[stu init]

当Student的instance对象要调用Person的对象时,会先通过isa找到student的class,然后通过superclass找到person的class,最后找到对象方法的实现进行调用,同样如果person发现自己没有响应的对象方法,又会通过Person的superclass指针找到NSObject的class对象,去寻找响应的方法。
(4)当类对象调用父类的类方法时,就需要先通过isa指针找到meta-class,然后通过superclass去寻找响应的方法。

[student personClassMethod];
[student load];
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用。

第二次学习

类对象

typedef struct objc_class *Class;

实例对象

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

优秀提问

  • 为什么不能通过runtime增加属性呢?

6、参考文章:(以上内容全部摘自下面作者的文章,我只改了格式)

猜你喜欢

转载自blog.csdn.net/u014544346/article/details/95357451