MST
星途 面试题库

面试题:Objective-C类别在运行时如何加载方法

请阐述Objective-C类别(Category)在运行时加载方法的具体过程,包括相关的数据结构和消息传递机制。
23.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

类别(Category)在运行时加载方法过程

  1. 编译阶段:编译器将Category的方法、属性、协议信息等收集起来,放到一个结构体category_t中。
  2. 加载阶段:运行时,Runtime系统会将Category的信息合并到类的相关数据结构中。具体来说,Category的方法会被添加到类的方法列表头部。这样做的原因是,Category通常用于为已有类添加新功能,放在头部能让新添加的方法优先被调用。
  3. 消息传递阶段:当发送一个消息给对象时,Runtime会根据对象的isa指针找到对应的类。在类的方法列表中查找方法实现。由于Category的方法在方法列表头部,所以会优先查找Category中实现的方法,如果找到就执行相应的实现代码。

相关的数据结构

  1. category_t:这是Category在运行时的核心数据结构,定义如下:
struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};

其中,name是Category的名称,cls指向被扩展的类,instanceMethodsclassMethods分别是实例方法列表和类方法列表,protocols是协议列表,instanceProperties是实例属性列表。 2. method_list_t:表示方法列表的数据结构,包含了一系列的method_t

struct method_list_t {
    struct entsize_list_tt<method_t, method_list_t> entsizeAndFlags;
    unsigned int count;

    method_t *first;
};
  1. method_t:代表一个方法,包含方法名、方法实现、方法类型编码等信息。
struct method_t {
    SEL name;
    const char *types;
    IMP imp;
    struct SortBySELAddress :
        public std::binary_function<const method_t&, const method_t&, bool>
    {
        bool operator() (const method_t& lhs, const method_t& rhs) const {
            return lhs.name < rhs.name;
        }
    };
};

消息传递机制

  1. 当向一个对象发送消息时,Runtime首先根据对象的isa指针找到对应的类。
  2. 在类的方法列表(包括本类方法列表和Category添加到头部的方法列表)中查找与消息对应的方法实现(通过SEL查找IMP)。如果在本类中没有找到,会沿着继承体系向上查找。
  3. 如果最终都没有找到方法实现,会进入动态方法解析阶段,尝试动态添加方法。若动态方法解析也无法处理,会进入备用接收者阶段,看是否有其他对象能处理该消息。若仍然无法处理,最后会进入消息转发阶段,通过完整的消息转发流程来处理消息,否则程序会崩溃。