MST

星途 面试题库

面试题:Objective-C中@selector()原理深度剖析及自定义实现探讨

深入讲解Objective-C中@selector()的底层原理,包括它如何将方法名转换为SEL类型,以及SEL在runtime中的数据结构和存储方式。假设你需要在一个简单的类库中自定义实现类似@selector()的功能,描述你的设计思路和关键实现步骤,同时分析这种自定义实现与原生@selector()可能存在的差异及应用场景。
40.5万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

@selector()底层原理

  1. 方法名转换为SEL类型
    • 在Objective - C中,@selector()是一个编译器指令。当编译器遇到@selector()时,它会在编译期将传入的方法名(字符串形式)转换为SEL类型。这个过程其实是通过查找预编译时生成的一个映射表来实现的。这个映射表将方法名(以字符串形式存储)与对应的SEL值关联起来。
    • 例如,对于一个类MyClass有方法-(void)myMethod;,当使用@selector(myMethod)时,编译器会在这个映射表中查找"myMethod"对应的SEL值并返回。
  2. SEL在runtime中的数据结构和存储方式
    • SEL本质上是一个typedef struct objc_selector *SEL;,它是一个指向objc_selector结构体的指针。在runtime中,SEL被用来唯一标识一个方法。
    • 存储方式上,runtime会为每个类维护一个方法列表,这个列表中每个方法都与一个SEL关联。并且,runtime有一个全局的缓存(高速缓存),用于快速查找SEL对应的方法实现。当一个方法被调用时,runtime首先在缓存中查找对应的SEL,如果找不到再去类的方法列表中查找。

自定义实现类似@selector()的设计思路和关键步骤

  1. 设计思路
    • 首先需要一个数据结构来存储方法名与自定义SEL的映射关系。可以使用哈希表(如NSMutableDictionary,在实际C实现中可使用自定义哈希表),以方法名字符串为键,自定义的SEL值为值。
    • 对于每个类,需要维护一个独立的映射表,因为不同类可能有同名方法。
  2. 关键步骤
    • 定义自定义SEL类型
      typedef int MySEL;
      
    • 创建映射表
      NSMutableDictionary<NSString *, MySEL> *classSelectorMap = [NSMutableDictionary dictionary];
      
    • 实现类似@selector()的函数
      MySEL mySelector(const char *methodName) {
          NSString *name = [NSString stringWithUTF8String:methodName];
          MySEL sel = [classSelectorMap[name] intValue];
          if (sel == 0) {
              static MySEL nextSel = 1;
              sel = nextSel++;
              classSelectorMap[name] = @(sel);
          }
          return sel;
      }
      

与原生@selector()的差异及应用场景

  1. 差异
    • 性能差异:原生@selector()是在编译期生成映射,效率极高。而自定义实现是在运行时构建映射,首次获取SEL时会有一定性能开销。
    • 唯一性:原生SEL在整个程序中是唯一的,不同类同名方法对应相同SEL。自定义实现中,如果不同类使用相同方法名,可能会生成不同的SEL值,除非进行特殊处理。
    • 系统集成:原生@selector()与runtime紧密集成,可直接用于消息发送等runtime操作。自定义实现则需要额外适配才能用于runtime相关操作。
  2. 应用场景
    • 学习与研究:自定义实现有助于深入理解@selector()的原理,适合学习Objective - C runtime机制。
    • 轻量级框架:在一些轻量级、对runtime依赖不深的类库中,自定义实现可以简化实现,避免引入过多runtime依赖。但对于大型、复杂的应用,原生@selector()因其高效性和与runtime的紧密集成更适合。