在Objective-C 源码中看看实例的定义
#if !OBJC_TYPES_DEFINED
/// 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;
#endif
通过代码可以看出id 是指向struct objc_object结构体的指针,struct objc_object结构体中只有一个成员变量Class类型isa,Class 是指向struct objc_class结构体的指针, 下面看看NSObject 的定义
@interface NSObject {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
通过代码可以看出NSObject也只有一个成员变量Class类型isa
id tempStr = [[NSString alloc] init];
NSString *tmpOneStr = [[NSString alloc] init];
以上两种方法都可以表示实例对象
下面看看struct objc_class结构体在runtime.h中
#if !OBJC_TYPES_DEFINED
/// An opaque type that represents a method in a class definition.
/** 方法别名 */
typedef struct objc_method *Method;
/// An opaque type that represents an instance variable.
/** 变量别名 */
typedef struct objc_ivar *Ivar;
/// An opaque type that represents a category.
/** 类别别名 */
typedef struct objc_category *Category;
/// An opaque type that represents an Objective-C declared property.
/** 属性别名 */
typedef struct objc_property *objc_property_t;
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; // 类的版本信息,默认为0
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 *` */
#endif
OC 中的类也是一个对象,称为类对象,类对象就是一个结构体struct objc_class,这个结构体存放的数据称为元数据(metadata),类对象在编译期用于创建实例对象,是单例。
看一下NSObject.mm中的代码
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
上面的类方法+ (Class)class和实例方法- (Class)class返回的都是类对象。
先看一下object_getClass方法
/**
* Returns the class of an object.
*
* @param obj The object you want to inspect.
*
* @return The class object of which \e object is an instance,
* or \c Nil if \e object is \c nil.
*/
OBJC_EXPORT Class _Nullable
object_getClass(id _Nullable obj)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
object_getClass 用于获取对象的isa指针指向的对象
验证类方法+ (Class)class和实例方法- (Class)class返回的都是类对象:
DMFunctionClassModel *tempModel = [[DMFunctionClassModel alloc] init];
if ([DMFunctionClassModel class] == [tempModel class]) {
NSLog(@"[DMFunctionClassModel class] 和 [tempModel class] 获取的是类对象");
}
输出如下
类对象的isa指针指向的我们称之为元类(metaClass),元类中保存了创建类对象以及类方法所需的所有信息
/**
* Returns a Boolean value that indicates whether a class object is a metaclass.
*
* @param cls A class object.
*
* @return \c YES if \e cls is a metaclass, \c NO if \e cls is a non-meta class,
* \c NO if \e cls is \c Nil.
*/
OBJC_EXPORT BOOL
class_isMetaClass(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
class_isMetaClass 用于判断Class 对象是否为元类
BOOL isMeta = class_isMetaClass(object_getClass([DMFunctionClassModel class]));
if (isMeta) {
NSLog(@"object_getClass([DMFunctionClassModel class]) 获取的是元类");
}
输出如下:
通过输出可以知道类对象的isa指针指向的是元类
下图清晰的展示了实例、类对象、元类之间的关系
下面区分一下
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
+ (BOOL)isSubclassOfClass:(Class)aClass;
这三个函数,可以看一下源码实现NSObject.mm中
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) {
return YES;
}
}
return NO;
}
+ (BOOL)isSubclassOfClass:(Class)cls {
for (Class tcls = self; tcls; tcls = tcls->superclass) {
if (tcls == cls) {
return YES;
}
}
return NO;
}
可以知道,isMemberOfClass只是判断类对象和传入的Class对象是否相同,isKindOfClass和isSubclassOfClass都会按照继承关系一层一层和传入的Class对象比较,直到nil为止。isKindOfClass和isSubclassOfClass的不同是一个是实例方法一个是类方法。