iOS笔记

浅谈iOS isa指针

2019-11-20  本文已影响0人  不会武功的陈真

为什么突然想写一篇关于isa的文章呢!是在写kvo原理的时候谈到了isa。有些同学就问我isa到底是什么。咱们就简单的看看

要讲isa 就要了解 instance(实例) class object(类对象) metaclass(元类)

instance(实例)

在我们开发的时候,总有时会用id来接收一些对象。但是大家想过id是怎么实现的吗?看下面这段代码,这是objc/objc.h里面摘出来的代码。
不难看出,id是一个objc_object类型的结构体指针,这个结构体里面只有一个 Class类型的变量isa(还有这个对象自己定义的相关属性等,这里就不讨论)。我们创建对象的时候,其实内部是创建了一个这样的结构体。

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

说道这里咱们明白了实例的本质,是一个结构体,里面包含了一个 Class类型的变量isa

class object(类对象) metaclass(元类)

什么是类对象,它也是这个类生成的一个对象(但是明显不是该类的实例,下面我会有验证),但是这个对象里面包含的东西更多,类对象是一个objc_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 *` */

这个结构体里面也包含Class类型 isa ,还有Class类型的 superClass,咱们这边只研究的这两个,其他的咱们暂时先不管

类对象怎么获取?最简单的方法[ClassName class],下面我们探究一下isa 和类对象关系
先给大家介绍两个方法
object_getClass用于获取对象的isa指针指向的对象
class_isMetaClass用于判断Class对象是否为元类
下面是代码

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Person: NSObject


@property(nonatomic,strong) NSString *tiantian;
@end

@implementation Person

+(void)tt{
    NSLog(@"tt");
}


@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        Person *p1 = [[Person alloc] init];
//---------------------------------------------------------------------------------
        //实例对象调用class方法 获取类对象
        NSLog(@"[p class] - %@",[p class]);
        //实例对象调用class方法 获取类对象
        NSLog(@"[p1 class] - %@",[p1 class]);
        //类名调用class方法 获取类对象
        NSLog(@"[Person class] - %@\n",[Person class]);
//---------------------------------------------------------------------------------
        //获取p的isa
        NSLog(@"object_getClass(p) - %@",object_getClass(p));
        //获取p1的isa
        NSLog(@"object_getClass(p1) - %@",object_getClass(p1));
        //获取类对象的isa
        NSLog(@"object_getClass([p class]) - %@",object_getClass([p class]));
        
 
//---------------------------------------------------------------------------------
    }
    return 0;
}

MyTextKVCKVO[5141:12156410] [p class] - Person
MyTextKVCKVO[5141:12156410] [p1 class] - Person
MyTextKVCKVO[5141:12156410] [Person class] - Person
MyTextKVCKVO[5141:12156410] object_getClass(p) - Person
MyTextKVCKVO[5141:12156410] object_getClass(p1) - Person
MyTextKVCKVO[5141:12156410] object_getClass([p class]) - Person

运行完了之后看结果 一脸懵逼。怎么都一样?????
我们就仔细的判断一下 具体是什么情况,再看下面的代码

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Person: NSObject


@property(nonatomic,strong) NSString *tiantian;
@end

@implementation Person

+(void)tt{
    NSLog(@"tt");
}


@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        Person *p1 = [[Person alloc] init];

        //输出 1 。 结论:不同对象的 类对象 是一样的
        NSLog(@"%d",[p class] == [p1 class]);
        //输出 1 , 实例对象获取的类对象 和 类名获取的类对象是一样的
        NSLog(@"%d",[p class] == [Person class]);
//---------------------------------------------------------------------------------
        //类对象 和 这个 p的isa是否相等
        NSLog(@"%d",[p class] == object_getClass(p));
        //类对象 和 这个 p1的isa是否相等
        NSLog(@"%d",[p class] == object_getClass(p1));
 
    }
    return 0;
}

MyTextKVCKVO[5228:12166573] 1
MyTextKVCKVO[5228:12166573] 1
MyTextKVCKVO[5228:12166573] 1
MyTextKVCKVO[5228:12166573] 1

根据上见面的结果咱们可以得出两个结论:
1、一个类的类对象(不管是对象获取,还是类名获取)都是同一个[Person class]
2、我们可以猜测一个类的所有实例对象的isa都是指向同一个 类对象[Person class]

在看superClass

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Person: NSObject


@property(nonatomic,strong) NSString *tiantian;
@end

@implementation Person

+(void)tt{
    NSLog(@"tt");
}


@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];

        //获取p的isa
        Class p_isa = object_getClass(p);
        NSLog(@"%@",p_isa);
        
        //获取类对象的superClass
        Class p_isa_superClass = class_getSuperclass(p_isa);
        NSLog(@"%@",p_isa_superClass);
        
        //获取p对象的isa 的 isa
        Class p_isa_isa = object_getClass(p_isa);
        NSLog(@"%@",p_isa_isa);
        
        //判断p的isa 和 (p对象的isa的isa)是否一样
        NSLog(@"%d",p_isa == p_isa_isa);
        
        //判断p_isa 是不是元类
        NSLog(@"%d",class_isMetaClass(p_isa));
        //判断p_isa_isa 是不是元类
        NSLog(@"%d",class_isMetaClass(p_isa_isa));
        
    }
    return 0;
}

MyTextKVCKVO[5433:12185744] Person
MyTextKVCKVO[5433:12185744] NSObject
MyTextKVCKVO[5433:12185744] Person
MyTextKVCKVO[5433:12185744] 0
MyTextKVCKVO[5433:12185744] 0
MyTextKVCKVO[5433:12185744] 1

总结:一个实例对象isa指向的是这个对象的类对象类对象isa指向的是 该类的元类
下面的图可以加强理解

910291-57780799dbe7fd12.png

咱们再想一下 superClass 也是Class对象,也会有isa 和superClass。所以就能一直找到顶层父类,下面是一个大神做的图,总结的很好,也容易懂。


851897-847ffb4b1d53ef23.png
上一篇下一篇

猜你喜欢

热点阅读