Objective-C中的 self 和 isa

2018-08-22  本文已影响96人  Jimm_鱼

isa指针

typedef struct objc_class *Class;
typedef struct objc_object *id;

id是一个objc_object 结构类型的指针,而objc_object结构就表示是一个对象。所以,id 声明的变量则是一个指向对象的指针。

我们所说的“对象”,就是指这样的一个结构体:objc_object,它的成员只有一个指向object_class结构体的指针isa

union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
}
struct objc_object {
private:
    isa_t isa;
}
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
}
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
@interface Object { 
    Class isa; 
}  

对象的实例方法调用时,通过对象的isa在类中获取方法的实现。
类对象的类方法调用时,通过类的isa在元类中获取方法的实现。

self、 super 和 _cmd

当使用self调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用super时,则从父类的方法列表中开始找。然后调用父类的这个方法。

selfsuper是一个指针,self谁调用了当前方法,self就指向谁
super指向了当前类的父类,如果super在类方法中,它就代表了调用当前类方法的类的父类,如果在对象方法中,它就代表调用当前对象方法的对象的父类对象

  1. 如果selfsuper在类方法中,那么它就代表当前调用这个类方法的类、父类
  2. 如果selfsuper在对象方法中,那么它就代表当前调用这个对象方法的对象、父对象
    出现在对象方法中,就代表着当前对象,出现在类方法中,就代表着当前类
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

struct objc_method {
        SEL method_name;
        char *method_types;
        IMP method_imp;
};

SELselectorObjc中的表示类型,selector是方法选择器
SEL可以理解为方法编号,其实它就是个映射到方法的C字符串,objc.h文件中

object_getClass 与 [self class]

  1. object_getClass: 获得的是isa指针的指向
  2. [self class]: 当self时实例对象的时候,获取的是isa的指向,也就是类对象,如果是类对象,则返回自身。
object_getClass [obj class]
实例对象 isa指针指向 isa指针指向
类对象 isa指针指向 对象本身
元类对象 isa指针指向 对象本身

关于 class 和 object_getClass的相关源码:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

inline Class 
objc_object::getIsa() 
{
    if (isTaggedPointer()) {
        uintptr_t slot = ((uintptr_t)this >> TAG_SLOT_SHIFT) & TAG_SLOT_MASK;
        return objc_tag_classes[slot];
    }
    return ISA();
}

inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
    return (Class)(isa.bits & ISA_MASK);
}
如下图所示:
  1. 类方法中 + (void)testSelfself是指向类对象本身,[Person class][self class]也都是指向本身,因为在类方法中self是类对象,所以和[Person class]一样调用的是+ (Class)class返回的都是自身,object_getClass(class)相当于是self->isa,所以是指向isa的指针

  2. 实例方法中 - (void)testSelf ,self是指向当前实例对象本身,在实例方法中的[Person class]和类方法中的p2指针地址一样,都是指向类对象本身,[self class]因为self是实例对象所以调用- (Class)class相当于调用object_getClass(class),返回的是self->isa,所以是指向isa指针。p2 == p3 == p4,这也说明了实例对象中的isa指针指向的是类对象。

附:(isKindOfClass 和 isMemberOfClass)源码

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

问题:以下代码输出结果?

BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];

答案和详解和可以从神经病院 Objective-C Runtime 入院第一天这里获取

参考链接

神经病院 Objective-C Runtime 入院第一天
从 NSObject 的初始化了解 isa

欢迎留言,如果写的不对的地方还请不吝指出。

上一篇 下一篇

猜你喜欢

热点阅读