美文网首页
Objective-C中的 self 和 isa

Objective-C中的 self 和 isa

作者: Jimm_鱼 | 来源:发表于2018-08-22 11:53 被阅读96次

isa指针

  • Class 和 id 的typedef
typedef struct objc_class *Class;
typedef struct objc_object *id;

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

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

  • isa_t
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
}
  • objc_object
struct objc_object {
private:
    isa_t isa;
}
  • objc_class
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
}
  • NSObject
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
@interface Object { 
    Class isa; 
}  
  • Objective-C对象基本上是C结构。每个Objective-C对象(包括每个类)都有一个isa指针,运行时根据此指针来确定对象是什么类,因此它知道对象响应的选择器,超类是什么,对象具有什么属性等等。

  • isa:是一个Class类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

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

self、 super 和 _cmd

  • self: Objective-C的函数的前两个隐藏参数之一,指向当前当前调用方法的类,另一个隐藏参数是_cmd,代表当前类方法的selector

  • super: super并不是隐藏的参数,它只是一个“编译器指示符”,它和self指向的是相同的消息接收者,不同的是super告诉编译器,当调用方法时,要去调用父类的方法,而不是本类里的。

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

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

  1. 如果selfsuper在类方法中,那么它就代表当前调用这个类方法的类、父类
  2. 如果selfsuper在对象方法中,那么它就代表当前调用这个对象方法的对象、父对象
    出现在对象方法中,就代表着当前对象,出现在类方法中,就代表着当前类
  • _cmd: SEL类型的一个变量,代表当前方法的selectorObjective-C的函数的前两个隐藏参数的另外一个,它和self一样都是每个方法调用时都会传入的参数
/// 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

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

相关文章

  • Objective-C中的 self 和 isa

    isa指针 Class 和 id 的typedef id是一个objc_object 结构类型的指针,而objc_...

  • Objective-C isa 指针 与 runtime 机制文

    一.isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和...

  • Objective-C isa 指针 与 runtime 机制

    一.isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和...

  • isa指针

    一.isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和...

  • ios - objectC 的isa 详解

    一.isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和...

  • Objective-C isa 指针 与 runtime 机制

    一.isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和...

  • isa 指针

    isa指针 要认识什么是isa指针,我们得先明确一点: 在Objective-C中,任何类的定义都是对象。类和类的...

  • iOS底层原理之isa指针

    isa指针 在Objective-C中,实例对象的isa指向类对象,类对象的isa指向元类对象.其实这样说是有一些...

  • Objective-C self与super的区别

    Objective-C self与super的区别 [self class] 和 [super class] 在当...

  • isa指针

    一.isa指针要认识什么是isa指针,我们得先明确一点:在Objective-C中,任何类的定义都是对象。类和类的...

网友评论

      本文标题:Objective-C中的 self 和 isa

      本文链接:https://www.haomeiwen.com/subject/lgieiftx.html