OC对象

对象

在 Objective-C 中,每一个对象都是某个类的实例,且这个对象的isa指针指向它所属的类。每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。每一个对象都可以接受消息,而对象能够接收的消息列表是保存在它所对应的类中。

在官方runtime(objc4-709)文件的NSObject.h

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

在objc.h中

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

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

runtime.h


struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

objc-runtime-old.h


struct objc_class : objc_object {

    Class superclass;
    const char *name;
    uint32_t version;
    uint32_t info;
    uint32_t instance_size;
    struct old_ivar_list *ivars;
    struct old_method_list **methodLists;
    Cache cache;
    struct old_protocol_list *protocols;
    // CLS_EXT only
    const uint8_t *ivar_layout;

    ......

}

objc.h

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

objc-privite.h

struct objc_object {
private:
    isa_t isa;
public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();

    ......
}

NSObject包含Class类型(结构体)的isa成员变量,class(objc_class)结构体继承自objc_object结构体。OC对象的本质是objc_object类型的结构体。

Objective-C中的类本质上也是对象,称之为类对象,它是某个类的实例,这个类称之为元类(metaclass)

为了设计上的完整,所有的元类的 isa 指针都会指向一个根元类 (root metaclass)。根元类 (root metaclass) 本身的 isa 指针指向自己,这样就行成了一个闭环。一个对象能够接收的消息列表是保存在它所对应的类中的。实例方法是保存在类中的,而类方法是保存在元类中的。

由于类方法的定义是保存在元类 (metaclass) 中,而方法调用的规则是,如果该类没有一个方法的实现,则向它的父类继续查找。所以,为了保证父类的类方法可以在子类中可以被调用,所以子类的元类会继承父类的元类,换而言之,类对象和元类对象有着同样的继承关系。

Category

因为对象在内存中的排布可以看成一个结构体,该结构体的大小并不能动态变化。所以无法在运行时动态给对象增加成员变量。 相对的,对象的方法定义都保存在类的可变区域中。Objective-C 2.0 并未在头文件中将实现暴露出来,但在 Objective-C 1.0 中,可以看到方法的定义列表是一个名为 methodLists的指针的指针。通过修改该指针指向的指针的值,就可以实现动态地为某一个类增加成员方法。这也是Category实现的原理。同时也说明了为什么Category只可为对象增加成员方法,却不能增加成员变量。

通过objc_setAssociatedObjectobjc_getAssociatedObject方法可以变相地给对象增加成员变量,但由于实现机制不一样,所以并不是真正改变了对象的内存结构

Method Swizzling

Objective-C 提供了以下 API 来动态替换类方法或实例方法的实现:

  • class_replaceMethod 替换类方法的定义
  • method_exchangeImplementations 交换 2 个方法的实现
  • method_setImplementation 设置 1 个方法的实现

从以上的区别我们可以总结出这 3 个 API 的使用场景:

  • class_replaceMethod, 当需要替换的方法可能有不存在的情况时,可以考虑使用该方法。
  • method_exchangeImplementations,当需要交换 2 个方法的实现时使用。
  • method_setImplementation 最简单的用法,当仅仅需要为一个方法设置其实现方式时使

results matching ""

    No results matching ""