浅谈iOS isa指针
为什么突然想写一篇关于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
总结:一个
910291-57780799dbe7fd12.png实例对象
的isa
指向的是这个对象的类对象
,类对象
的isa
指向的是 该类的元类
。
下面的图可以加强理解
咱们再想一下 superClass 也是Class对象,也会有isa 和superClass。所以就能一直找到顶层父类,下面是一个大神做的图,总结的很好,也容易懂。
851897-847ffb4b1d53ef23.png