12-2.【OC】【Swift+OC 混编】Swift 类型如何映射到 Objective-C?

6 阅读3分钟

Swift 类型映射到 Objective-C 的过程是由 Swift 编译器(Clang 与 Swift 编译器前端)通过生成的 -Swift.h 桥接头文件 自动完成的。

由于 Swift 是静态强类型且支持值类型,而 Objective-C 几乎一切皆对象,这种映射本质上是**“类型降级”“引用封装”**的过程。


1. 基础数据类型的映射

Swift 的基础类型通过 Swift 标准库与 Foundation 框架的深度集成,实现了自动桥接。

Swift 类型Objective-C 类型映射机制
Int, Float, Double, BoolNSInteger, float, double, BOOL直接映射为 C 标量类型。
StringNSString * _Nonnull自动桥接,处理值拷贝与引用。
Array<Element>NSArray<Element> *泛型会尽可能保留(如果 Element 兼容 OC)。
Dictionary<Key, Value>NSDictionary<Key, Value> *同上。
Optional<T>T _NullableT _Nonnull映射为指针的 nil 可靠性。

2. 引用类型 (Class)

Swift 的类要映射到 OC,必须满足两个条件:继承自 NSObject 且标记为 @objc

  • 成员变量与属性:Swift 属性会映射为 OC 的 @property。Swift 的 let 属性在 OC 中表现为 readonly
  • 初始化器:Swift 的 init 会映射为 OC 的 initWith... 风格的方法。
  • 方法名转换:Swift 的参数标签会转化为 OC 的方法签名,例如 func move(to point: CGPoint) 映射为 - (void)moveToPoint:(CGPoint)point

3. 值类型 (Struct & Enum)

这是映射中最受限的部分,因为 OC 不支持 Swift 的现代值类型特征。

结构体 (Struct)

  • 原生 Struct 无法直接映射:OC 无法识别 Swift 的 struct
  • 对策:必须将 Struct 包装在 NSObject 的类中,或者使用符合 OC 规范的 C Struct(但这将失去 Swift 结构体的方法特性)。

枚举 (Enum)

  • 简单枚举:只要指定为 Int 原始值(Raw Value)并标记为 @objc,可以映射为 NS_ENUM
  • 带关联值的枚举 (Associated Values)无法映射。OC 的枚举只是简单的整数,无法承载 Swift 枚举复杂的内存布局(Tagged Unions)。

4. 特殊类型的特殊处理

闭包 (Closures) vs 块 (Blocks)

Swift 的闭包会自动映射为 OC 的 Block

  • Swift:(Int) -> String
  • OC:NSString * (^)(NSInteger)

注意:映射过程中,编译器会自动处理逃逸(Escaping)语义和内存管理。

协议 (Protocol)

如前所述,只有标记为 @objc 的协议才能映射。OC 无法理解 Swift 协议的关联类型(associatedtype)和泛型约束。

指针 (Pointers)

Swift 的安全指针与非安全指针会映射为相应的 C 指针类型:

  • UnsafePointer<T> 映射为 const T *
  • UnsafeMutableRawPointer 映射为 void *

5. 映射中的“修饰符”转换

编译器会根据 Swift 的修饰符在 -Swift.h 中添加对应的宏:

  • weak:映射为 __weak
  • unowned:映射为 __unsafe_unretained(OC 中没有完全等价的非拥有引用)。
  • throwing:映射为带 NSError ** 参数的方法,并返回 BOOL 或可选值。

💡 避坑指南:映射失效

如果你的 Swift 类中包含 元组 (Tuples)泛型结构体嵌套类型,这些成员在生成的 .h 文件中会直接消失,因为 Objective-C 没有任何语法能表达它们。