Swift 与 OC 混编底层交互原理 - 实践

前言

Swift 和 Objective-C 的混编是 iOS 开发中的常见场景。无论是老项目引入 Swift,还是 Swift 项目使用 OC 第三方库,都需要两种语言之间的互操作。

本文将深入探讨 Swift 与 OC 混编的底层实现原理,包括:桥接机制、内存模型差异、方法调度、类型转换等核心内容。


一、混编基础架构

1.1 混编的两种方向

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift 与 OC 混编方向                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   【方向 1: OC 调用 Swift】                                          │
│                                                                      │
│   ┌─────────────────┐         ┌─────────────────┐                   │
│   │  Objective-C    │         │     Swift       │                   │
│   │                 │         │                 │                   │
│   │  #import        │         │  @objc          │                   │
│   │  "ModuleName-   │ ──────> │  class MyClass  │                   │
│   │   Swift.h"      │         │                 │                   │
│   │                 │         │  @objc          │                   │
│   │  [obj method]   │         │  func method()  │                   │
│   └─────────────────┘         └─────────────────┘                   │
│                                                                      │
│   ════════════════════════════════════════════════════════════════  │
│                                                                      │
│   【方向 2: Swift 调用 OC】                                          │
│                                                                      │
│   ┌─────────────────┐         ┌─────────────────┐                   │
│   │     Swift       │         │  Objective-C    │                   │
│   │                 │         │                 │                   │
│   │  import Module  │         │  @interface     │                   │
│   │  或             │ ──────> │  MyClass        │                   │
│   │  桥接头文件      │         │                 │                   │
│   │                 │         │  - (void)method │                   │
│   │  obj.method()   │         │                 │                   │
│   └─────────────────┘         └─────────────────┘                   │
│                                                                      │
│   关键文件:                                                         │
│   • xxx-Bridging-Header.h : Swift 调用 OC 的桥接头文件              │
│   • xxx-Swift.h : OC 调用 Swift 的自动生成头文件                    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

1.2 桥接头文件机制

┌─────────────────────────────────────────────────────────────────────┐
│                    桥接头文件工作原理                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   【Bridging Header - Swift 访问 OC】                               │
│                                                                      │
│   MyApp-Bridging-Header.h                                           │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  // 导入需要在 Swift 中使用的 OC 头文件                      │   │
│   │  #import "MyOCClass.h"                                       │   │
│   │  #import "LegacyHelper.h"                                    │   │
│   │  #import                      │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼                                          │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Swift 编译器 (Clang Importer)                               │   │
│   │                                                              │   │
│   │  1. 解析 OC 头文件                                           │   │
│   │  2. 将 OC 接口转换为 Swift 接口                              │   │
│   │  3. 生成 Swift 可用的模块声明                                │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼                                          │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Swift 代码中可以直接使用                                    │   │
│   │                                                              │   │
│   │  let obj = MyOCClass()                                       │   │
│   │  obj.someMethod()                                            │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│   ════════════════════════════════════════════════════════════════  │
│                                                                      │
│   【Generated Header - OC 访问 Swift】                               │
│                                                                      │
│   Swift 源码                                                         │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  @objc public class NetworkManager: NSObject {               │   │
│   │      @objc public func fetchData() { }                       │   │
│   │  }                                                           │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼  编译时自动生成                          │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  MyApp-Swift.h (自动生成,不要手动编辑)                      │   │
│   │                                                              │   │
│   │  SWIFT_CLASS("_TtC5MyApp14NetworkManager")                   │   │
│   │  @interface NetworkManager : NSObject                        │   │
│   │  - (void)fetchData;                                          │   │
│   │  - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;   │   │
│   │  @end                                                        │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼                                          │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  OC 代码中使用                                               │   │
│   │                                                              │   │
│   │  #import "MyApp-Swift.h"                                     │   │
│   │                                                              │   │
│   │  NetworkManager *manager = [[NetworkManager alloc] init];    │   │
│   │  [manager fetchData];                                        │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

1.3 模块化与混编

// Framework 中的混编更复杂
// 需要使用 umbrella header 和 module.modulemap
// MyFramework.h (Umbrella Header)
#import <MyFramework/PublicOCClass.h>
  #import <MyFramework/AnotherOCClass.h>
    // module.modulemap
    framework module MyFramework {
    umbrella header "MyFramework.h"
    export *
    module * { export * }
    }
    // Swift 类需要 @objc 和 public
    @objc public class SwiftClass: NSObject {
    @objc public func publicMethod() { }
    }

二、@objc 与 @objcMembers 深度解析

2.1 @objc 的作用

// @objc 将 Swift 声明暴露给 Objective-C 运行时
// 1. 基本用法
@objc class MyClass: NSObject {
@objc var name: String = ""
@objc func doSomething() { }
}
// 2. 自定义 OC 中的名称
@objc(MYCustomClass)
class MyClass: NSObject {
@objc(customName)
var name: String = ""
@objc(doSomethingWithParam:)
func doSomething(param: String) { }
}
// 在 OC 中:
// MYCustomClass *obj = [[MYCustomClass alloc] init];
// obj.customName = @"test";
// [obj doSomethingWithParam:@"value"];

2.2 @objc 的底层实现

┌─────────────────────────────────────────────────────────────────────┐
│                    @objc 底层实现                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Swift 类定义:                                                      │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  @objc class Person: NSObject {                              │   │
│   │      @objc var age: Int = 0                                  │   │
│   │      @objc func sayHello() { print("Hello") }                │   │
│   │  }                                                           │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼ 编译后生成                               │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  ObjC 类结构 (class_ro_t)                                    │   │
│   │                                                              │   │
│   │  类名: _TtC8MyModule6Person (Swift mangled name)            │   │
│   │                                                              │   │
│   │  方法列表 (method_list_t):                                   │   │
│   │  ┌─────────────────────────────────────────────────────┐    │   │
│   │  │ SEL: age         │ IMP: swift_getProperty_impl      │    │   │
│   │  │ SEL: setAge:     │ IMP: swift_setProperty_impl      │    │   │
│   │  │ SEL: sayHello    │ IMP: _$s8MyModule6PersonC8sayHello │   │   │
│   │  │ SEL: init        │ IMP: _$s8MyModule6PersonCACycfc   │    │   │
│   │  └─────────────────────────────────────────────────────┘    │   │
│   │                                                              │   │
│   │  属性列表 (property_list_t):                                 │   │
│   │  ┌─────────────────────────────────────────────────────┐    │   │
│   │  │ name: age  │ attributes: T@"NSNumber",&,N,Vage      │    │   │
│   │  └─────────────────────────────────────────────────────┘    │   │
│   │                                                              │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│   @objc 做了什么:                                                   │
│   1. 在 ObjC 运行时注册类                                           │
│   2. 为方法生成 SEL 和 ObjC 兼容的 IMP                              │
│   3. 生成属性的 getter/setter                                       │
│   4. 处理 Swift 类型到 ObjC 类型的桥接                              │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

2.3 @objcMembers 批量暴露

// @objcMembers 自动为所有成员添加 @objc
@objcMembers
class DataManager: NSObject {
var items: [String] = []        // 自动 @objc
func addItem(_ item: String) { } // 自动 @objc
func removeItem(at index: Int) { } // 自动 @objc
// 私有成员不会暴露
private func internalMethod() { }
// 不兼容 ObjC 的类型不会暴露
func processData(_ data: (Int, Int)) { } // 元组不兼容,不暴露
}
// 等价于:
class DataManager: NSObject {
@objc var items: [String] = []
@objc func addItem(_ item: String) { }
@objc func removeItem(at index: Int) { }
}

2.4 @objc 的限制

// 以下类型不能用 @objc
// 1. 结构体
struct Point {  // ❌ 不能 @objc
var x: Double
var y: Double
}
// 2. 枚举(除非是 Int 类型)
enum Status {  // ❌ 不能 @objc
case active, inactive
}
@objc enum IntStatus: Int {  // ✅ Int 枚举可以
case active = 0
case inactive = 1
}
// 3. 泛型
class Container<T> {  // ❌ 泛型类不能 @objc
  var value: T?
  }
  // 4. 元组
  @objc func returnTuple() -> (Int, Int) { }  // ❌ 不能
  // 5. Swift 独有特性
  @objc func withDefaultParam(value: Int = 0) { }  // ❌ 默认参数不生效
  @objc func variadic(_ values: Int...) { }  // ❌ 可变参数不能
  // 6. 嵌套类型
  class Outer {
  @objc class Inner: NSObject { }  // ❌ 嵌套类型不能 @objc
  }

三、方法调度机制对比

3.1 Swift 方法调度类型

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift 方法调度方式                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   【1. 静态调度 (Static Dispatch)】                                  │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  • 编译时确定调用地址                                        │   │
│   │  • 无运行时开销,可内联优化                                  │   │
│   │                                                              │   │
│   │  适用于:                                                     │   │
│   │  • 结构体/枚举的方法                                         │   │
│   │  • final 类的方法                                           │   │
│   │  • private/fileprivate 方法                                 │   │
│   │  • 类的 static 方法                                         │   │
│   │                                                              │   │
│   │  struct Point {                                              │   │
│   │      func distance() -> Double { ... }  // 静态调度         │   │
│   │  }                                                           │   │
│   │                                                              │   │
│   │  final class Manager {                                       │   │
│   │      func process() { ... }  // 静态调度                    │   │
│   │  }                                                           │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│   【2. 虚表调度 (V-Table Dispatch)】                                 │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  • 类似 C++ 虚函数表                                         │   │
│   │  • 通过类的虚表查找方法地址                                  │   │
│   │                                                              │   │
│   │  适用于:                                                     │   │
│   │  • 类的普通实例方法(可被继承/重写)                         │   │
│   │                                                              │   │
│   │  class Animal {                                              │   │
│   │      func speak() { print("...") }  // V-Table              │   │
│   │  }                                                           │   │
│   │  class Dog: Animal {                                         │   │
│   │      override func speak() { print("Woof") }                │   │
│   │  }                                                           │   │
│   │                                                              │   │
│   │  V-Table 结构:                                               │   │
│   │  ┌────────────────────────────────────────────┐             │   │
│   │  │ Animal vtable:                             │             │   │
│   │  │   [0] speak -> Animal.speak                │             │   │
│   │  ├────────────────────────────────────────────┤             │   │
│   │  │ Dog vtable:                                │             │   │
│   │  │   [0] speak -> Dog.speak (override)        │             │   │
│   │  └────────────────────────────────────────────┘             │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│   【3. 消息调度 (Message Dispatch)】                                 │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  • ObjC runtime 的 objc_msgSend                             │   │
│   │  • 最灵活但最慢                                              │   │
│   │  • 支持 Method Swizzling、KVO 等                            │   │
│   │                                                              │   │
│   │  适用于:                                                     │   │
│   │  • 继承自 NSObject 的 @objc 方法                            │   │
│   │  • @objc dynamic 方法                                       │   │
│   │                                                              │   │
│   │  class ViewController: UIViewController {                    │   │
│   │      @objc dynamic func handleTap() { }  // 消息调度        │   │
│   │  }                                                           │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│   【4. Witness Table (协议)】                                        │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  • 用于协议类型的方法调度                                    │   │
│   │                                                              │   │
│   │  protocol Drawable {                                         │   │
│   │      func draw()                                             │   │
│   │  }                                                           │   │
│   │                                                              │   │
│   │  let items: [Drawable] = [Circle(), Square()]               │   │
│   │  for item in items {                                        │   │
│   │      item.draw()  // 通过 witness table 调度                │   │
│   │  }                                                           │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

3.2 @objc dynamic 的必要性

// 场景:需要 ObjC 运行时特性
// 1. KVO 监听
class Person: NSObject {
// ❌ 普通 @objc 属性,KVO 可能不工作
@objc var name: String = ""
// ✅ @objc dynamic 确保使用消息调度,KVO 正常工作
@objc dynamic var age: Int = 0
}
// 使用
let person = Person()
person.addObserver(self, forKeyPath: "age", options: .new, context: nil)
person.age = 25  // 触发 KVO
// 2. Method Swizzling
class ViewController: UIViewController {
// ❌ V-Table 调度,不能 swizzle
override func viewDidLoad() { }
// ✅ 消息调度,可以 swizzle
@objc dynamic func customMethod() { }
}
// 3. 选择器
class Handler: NSObject {
// 需要 @objc 才能用 #selector
@objc func handleTap(_ sender: UIButton) { }
}
let button = UIButton()
button.addTarget(handler, action: #selector(Handler.handleTap(_:)), for: .touchUpInside)

3.3 调度方式性能对比

┌─────────────────────────────────────────────────────────────────────┐
│                    方法调度性能对比                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   调度方式        │  相对速度  │  说明                               │
│   ───────────────┼───────────┼───────────────────────────────────   │
│   静态调度        │  最快 1x  │  编译时确定,可内联                  │
│   V-Table        │  快 ~1.2x │  一次间接跳转                        │
│   Witness Table  │  中 ~2x   │  额外的 existential 开销            │
│   消息调度        │  慢 ~4x   │  运行时查找,缓存未命中更慢          │
│                                                                      │
│   注意:这是理论值,实际差异在大多数场景中可忽略                     │
│   应根据功能需求选择,而不是过早优化                                 │
│                                                                      │
│   ════════════════════════════════════════════════════════════════  │
│                                                                      │
│   性能敏感场景的建议:                                               │
│                                                                      │
│   // 高频调用使用 final 或 struct                                   │
│   final class FastProcessor {                                        │
│       func process(_ data: [Int]) { ... }                           │
│   }                                                                  │
│                                                                      │
│   struct MathHelper {                                                │
│       func calculate(_ x: Double) -> Double { ... }                 │
│   }                                                                  │
│                                                                      │
│   // 需要动态特性时才用 @objc dynamic                               │
│   class ViewModel: NSObject {                                        │
│       @objc dynamic var data: [String] = []  // 需要 KVO           │
│       func processData() { ... }  // 不需要 @objc                   │
│   }                                                                  │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

四、类型桥接机制

4.1 自动桥接类型

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift - ObjC 类型桥接                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Swift 类型          │  ObjC 类型           │  桥接方式             │
│   ───────────────────┼─────────────────────┼────────────────────   │
│   String              │  NSString           │  零开销桥接           │
│   Array               │  NSArray            │  零开销桥接           │
│   Dictionary          │  NSDictionary       │  零开销桥接           │
│   Set                 │  NSSet              │  零开销桥接           │
│   Int, UInt, Float... │  NSNumber           │  装箱/拆箱            │
│   Bool                │  BOOL / NSNumber    │  装箱/拆箱            │
│   Data                │  NSData             │  零开销桥接           │
│   Date                │  NSDate             │  零开销桥接           │
│   URL                 │  NSURL              │  零开销桥接           │
│   Error               │  NSError            │  零开销桥接           │
│   AnyObject           │  id                 │  直接对应             │
│   Any                 │  id                 │  装箱                 │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

4.2 零开销桥接原理

// String 和 NSString 共享相同的内存布局
// 桥接时不需要复制数据
let swiftString: String = "Hello"
let nsString: NSString = swiftString as NSString  // 无复制
// 底层实现
// String 内部可以存储:
// 1. 小字符串 (Small String) - 内联存储
// 2. Native Swift String - Swift 管理的堆内存
// 3. Bridged NSString - 直接引用 NSString 对象
// 当 as NSString 时:
// - 如果是 Native String,创建一个 NSString wrapper
// - 如果已经是 Bridged NSString,直接返回
// 验证零开销
import Foundation
func testBridging() {
let str: NSString = "Test"
let swiftStr = str as String
// 两者指向相同的存储
str.withCString { ptr1 in
swiftStr.withCString { ptr2 in
print("Same storage: \(ptr1 == ptr2)")  // 可能为 true
}
}
}

4.3 装箱类型的开销

// 值类型到 AnyObject/id 需要装箱
// 1. 数字类型装箱
let intValue: Int = 42
let nsNumber = intValue as NSNumber  // 创建 NSNumber 对象
// 底层:
// NSNumber *number = [[NSNumber alloc] initWithLongLong:42];
// 2. Any 的装箱
func sendToOC(_ value: Any) {
// 如果是值类型,需要装箱
}
sendToOC(42)      // Int 装箱为 NSNumber
sendToOC("test")  // String 桥接为 NSString(零开销)
sendToOC(true)    // Bool 装箱为 NSNumber
// 3. 避免不必要的装箱
// ❌ 低效
func processNumbers(_ numbers: [Any]) {
for n in numbers {
if let int = n as? Int {
// 每次需要拆箱
}
}
}
// ✅ 高效
func processNumbers(_ numbers: [Int]) {
for n in numbers {
// 直接使用,无装箱/拆箱
}
}

4.4 自定义类型桥接

// 通过 _ObjectiveCBridgeable 协议实现自定义桥接
// ObjC 类
@interface LegacyPoint : NSObject
@property (nonatomic) double x;
@property (nonatomic) double y;
@end
// Swift 结构体
struct Point {
var x: Double
var y: Double
}
// 实现桥接
extension Point: _ObjectiveCBridgeable {
typealias _ObjectiveCType = LegacyPoint
func _bridgeToObjectiveC() -> LegacyPoint {
let obj = LegacyPoint()
obj.x = x
obj.y = y
return obj
}
static func _forceBridgeFromObjectiveC(_ source: LegacyPoint,
result: inout Point?) {
result = Point(x: source.x, y: source.y)
}
static func _conditionallyBridgeFromObjectiveC(_ source: LegacyPoint,
result: inout Point?) -> Bool {
result = Point(x: source.x, y: source.y)
return true
}
static func _unconditionallyBridgeFromObjectiveC(_ source: LegacyPoint?) -> Point {
guard let source = source else {
return Point(x: 0, y: 0)
}
return Point(x: source.x, y: source.y)
}
}
// 使用
let point = Point(x: 1.0, y: 2.0)
let legacyPoint = point as LegacyPoint  // 自动桥接
let backToSwift = legacyPoint as Point  // 自动桥接

五、内存管理互操作

5.1 ARC 在两种语言中的对应

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift 与 OC 内存管理对应                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   Swift 所有权        │  OC 等价物                                   │
│   ───────────────────┼────────────────────────────────────────────  │
│   strong (默认)       │  strong / retain                            │
│   weak               │  weak                                        │
│   unowned            │  unsafe_unretained (但更安全)                │
│   unowned(unsafe)    │  unsafe_unretained                           │
│                                                                      │
│   ════════════════════════════════════════════════════════════════  │
│                                                                      │
│   【属性修饰符对应】                                                 │
│                                                                      │
│   Swift:                           ObjC:                            │
│   ┌─────────────────────────┐     ┌─────────────────────────────┐  │
│   │ var delegate: Delegate? │     │ @property (weak) id delegate│  │
│   │ weak var ...            │     │                             │  │
│   └─────────────────────────┘     └─────────────────────────────┘  │
│                                                                      │
│   ┌─────────────────────────┐     ┌─────────────────────────────┐  │
│   │ var name: String        │     │ @property (strong) NSString │  │
│   │                         │     │ *name;                      │  │
│   └─────────────────────────┘     └─────────────────────────────┘  │
│                                                                      │
│   ┌─────────────────────────┐     ┌─────────────────────────────┐  │
│   │ unowned var parent:     │     │ @property (unsafe_unretained)│ │
│   │ Parent                  │     │ Parent *parent;             │  │
│   └─────────────────────────┘     └─────────────────────────────┘  │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

5.2 闭包/Block 的内存管理

// Swift 闭包和 OC Block 的互操作
// 1. Swift 闭包传给 OC
class NetworkManager: NSObject {
@objc func request(completion: @escaping (Data?, Error?) -> Void) {
// Swift 闭包被转换为 OC Block
// @escaping 确保闭包可以在方法返回后调用
DispatchQueue.global().async {
let data = Data()
completion(data, nil)
}
}
}
// OC 端使用:
// [manager requestWithCompletion:^(NSData *data, NSError *error) {
//     // ...
// }];
// 2. OC Block 在 Swift 中使用
// OC 定义:
// typedef void (^CompletionBlock)(BOOL success);
// - (void)performWithCompletion:(CompletionBlock)completion;
// Swift 使用:
let ocClass = SomeOCClass()
ocClass.perform { success in
print("Completed: \(success)")
}
// 3. 循环引用问题
class ViewController: UIViewController {
var networkManager = NetworkManager()
var data: Data?
func loadData() {
// ❌ 循环引用
networkManager.request { data, error in
self.data = data  // self 强引用
}
// ✅ 使用 weak
networkManager.request { [weak self] data, error in
self?.data = data
}
// ✅ 或 unowned (确定 self 不会先被释放)
networkManager.request { [unowned self] data, error in
self.data = data
}
}
}

5.3 Unmanaged 类型

// 处理手动内存管理的 Core Foundation 类型
// 1. 获取未管理引用
let unmanagedString = Unmanaged.passUnretained("Hello" as CFString)
let cfString = unmanagedString.takeUnretainedValue()
// 2. 转移所有权
func createCFString() -> Unmanaged<CFString> {
  let str = "Hello" as CFString
  return Unmanaged.passRetained(str)  // +1 retain
  }
  let unmanaged = createCFString()
  let str = unmanaged.takeRetainedValue()  // 接管所有权,平衡 retain
  // 3. 与 OC API 交互
  // 某些 C/OC API 返回未管理的对象
  let addressBook = ABAddressBookCreate()?.takeRetainedValue()
  // 4. 使用 __bridge
  // Swift 中等价于:
  let cfStr = unsafeBitCast("Hello" as NSString, to: CFString.self)

六、协议互操作

6.1 @objc protocol

// 可以被 OC 类实现的协议
@objc protocol DataSource: AnyObject {
// 必须实现
func numberOfItems() -> Int
func item(at index: Int) -> Any
// 可选方法
@objc optional func title() -> String?
@objc optional var headerView: UIView? { get }
}
// OC 实现:
// @interface MyDataSource : NSObject <DataSource>
  // @end
  // 
  // @implementation MyDataSource
  // - (NSInteger)numberOfItems { return 10; }
  // - (id)itemAtIndex:(NSInteger)index { return @"item"; }
  // // 可选方法可以不实现
  // @end
  // Swift 使用:
  class ViewController: UIViewController {
  weak var dataSource: DataSource?
  func loadData() {
  guard let ds = dataSource else { return }
  let count = ds.numberOfItems()
  // 可选方法需要特殊调用
  if let title = ds.title?() {
  print(title)
  }
  // 或者检查是否响应
  if ds.responds(to: #selector(DataSource.title)) {
  // ...
  }
  }
  }

6.2 Swift 协议 vs OC 协议

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift 协议 vs OC 协议                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   特性              │  Swift 协议         │  @objc 协议             │
│   ─────────────────┼───────────────────┼─────────────────────────  │
│   值类型实现         │  ✅ 支持           │  ❌ 不支持              │
│   泛型/关联类型      │  ✅ 支持           │  ❌ 不支持              │
│   静态方法要求       │  ✅ 支持           │  ✅ 支持 (+方法)        │
│   可选方法          │  ❌ 需要默认实现    │  ✅ @objc optional     │
│   运行时检查        │  ❌ 编译时          │  ✅ responds(to:)       │
│   方法调度          │  Witness Table    │  消息发送               │
│   OC 互操作         │  ❌ 不可见         │  ✅ 完全兼容            │
│                                                                      │
│   ════════════════════════════════════════════════════════════════  │
│                                                                      │
│   【何时使用 @objc protocol】                                        │
│                                                                      │
│   1. 需要 OC 代码实现                                                │
│   @objc protocol LegacyDelegate {                                    │
│       func legacyCallback()                                          │
│   }                                                                  │
│                                                                      │
│   2. 需要可选方法                                                    │
│   @objc protocol DataSource {                                        │
│       @objc optional func supplementaryData() -> Any?               │
│   }                                                                  │
│                                                                      │
│   3. 需要运行时检查                                                  │
│   if object.responds(to: #selector(SomeProtocol.optionalMethod)) {  │
│       // ...                                                         │
│   }                                                                  │
│                                                                      │
│   【何时使用纯 Swift 协议】                                          │
│                                                                      │
│   1. 纯 Swift 项目                                                   │
│   protocol Identifiable {                                            │
│       associatedtype ID: Hashable                                   │
│       var id: ID { get }                                            │
│   }                                                                  │
│                                                                      │
│   2. 需要泛型/关联类型                                               │
│   protocol Container {                                               │
│       associatedtype Element                                        │
│       var items: [Element] { get }                                  │
│   }                                                                  │
│                                                                      │
│   3. 值类型需要实现                                                  │
│   protocol Drawable {                                                │
│       func draw()                                                    │
│   }                                                                  │
│   struct Circle: Drawable { ... }  // 结构体实现                    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

6.3 协议扩展与 OC

// 协议扩展的方法对 OC 不可见
protocol Greetable {
func greet() -> String
}
extension Greetable {
// 默认实现 - OC 不可见
func greet() -> String {
return "Hello"
}
// 扩展方法 - OC 不可见
func greetLoudly() -> String {
return greet().uppercased()
}
}
@objc protocol ObjCGreetable: Greetable {
// 必须声明在协议中的方法才对 OC 可见
@objc func greet() -> String
}
class Greeter: NSObject, ObjCGreetable {
// 必须提供实现
func greet() -> String {
return "Hi"
}
}
// OC 只能调用 greet,不能调用 greetLoudly

七、泛型与混编

7.1 泛型的限制

// Swift 泛型不能直接暴露给 OC
// ❌ 不能 @objc
class Container<T> {
  var items: [T] = []
  }
  // ❌ 泛型方法也不能
  class Manager: NSObject {
  @objc func process<T>(_ item: T) { }  // 编译错误
    }
    // ✅ 变通方案1:使用类型擦除
    class AnyContainer: NSObject {
    private var items: [Any] = []
    @objc func addItem(_ item: Any) {
    items.append(item)
    }
    @objc func getItem(at index: Int) -> Any? {
    guard index < items.count else { return nil }
    return items[index]
    }
    }
    // ✅ 变通方案2:使用协议
    @objc protocol Processable {
    func process()
    }
    class Manager: NSObject {
    @objc func processItem(_ item: Processable) {
    item.process()
    }
    }
    // ✅ 变通方案3:具体类型子类
    class StringContainer: NSObject {
    var items: [String] = []
    @objc func addItem(_ item: String) {
    items.append(item)
    }
    }

7.2 OC 轻量泛型

// OC 的轻量泛型 (Lightweight Generics)
// 只提供编译时检查,运行时会擦除
@interface Container<ObjectType> : NSObject
  @property (nonatomic, strong) NSMutableArray<ObjectType> *items;
    - (void)addItem:(ObjectType)item;
    - (ObjectType)itemAtIndex:(NSUInteger)index;
    @end
    // Swift 中可以使用类型参数
    let container = Container<NSString>()
      container.addItem("Hello")
      let item: String = container.item(at: 0) as String

八、错误处理互操作

8.1 Swift Error 与 NSError

// Swift Error 自动桥接到 NSError
// 1. 定义 Swift Error
enum NetworkError: Error {
case noConnection
case timeout
case invalidResponse(code: Int)
}
// 2. 暴露给 OC
class NetworkManager: NSObject {
@objc func fetchData() throws -> Data {
throw NetworkError.timeout
}
}
// OC 中使用:
// NSError *error = nil;
// NSData *data = [manager fetchDataAndReturnError:&error];
// if (error) {
//     NSLog(@"Error: %@", error);
// }
// 3. 自定义 NSError 信息
extension NetworkError: LocalizedError {
var errorDescription: String? {
switch self {
case .noConnection:
return "No internet connection"
case .timeout:
return "Request timed out"
case .invalidResponse(let code):
return "Invalid response: \(code)"
}
}
}
extension NetworkError: CustomNSError {
static var errorDomain: String {
return "com.app.NetworkError"
}
var errorCode: Int {
switch self {
case .noConnection: return 1001
case .timeout: return 1002
case .invalidResponse(let code): return code
}
}
var errorUserInfo: [String: Any] {
return [
NSLocalizedDescriptionKey: errorDescription ?? "Unknown error"
]
}
}

8.2 OC 方法的错误处理

// OC 方法在 Swift 中变成 throws
// OC 定义:
// - (BOOL)saveData:(NSData *)data error:(NSError **)error;
// - (NSData *)loadDataWithError:(NSError **)error;
// Swift 使用:
let manager = DataManager()
// 返回 Bool 的变成 throws -> Void
do {
try manager.save(data)
} catch {
print("Save failed: \(error)")
}
// 返回对象的变成 throws -> Object
do {
let data = try manager.loadData()
// 使用 data
} catch {
print("Load failed: \(error)")
}
// 或使用 try?
let data = try? manager.loadData()  // 失败返回 nil
// 或使用 try!(确定不会失败时)
let data = try! manager.loadData()  // 失败会崩溃

九、Selector 与方法引用

9.1 #selector 的使用

// #selector 需要 @objc 方法
class ViewController: UIViewController {
@objc func handleTap(_ sender: UITapGestureRecognizer) {
print("Tapped")
}
@objc func handleButton(_ sender: UIButton) {
print("Button pressed")
}
override func viewDidLoad() {
super.viewDidLoad()
// 使用 #selector
let tap = UITapGestureRecognizer(
target: self,
action: #selector(handleTap(_:))
)
view.addGestureRecognizer(tap)
let button = UIButton()
button.addTarget(
self,
action: #selector(handleButton(_:)),
for: .touchUpInside
)
}
}
// 获取方法的 Selector
let selector = #selector(ViewController.handleTap(_:))
print(selector)  // handleTap:

9.2 方法的 Selector 命名

class Calculator: NSObject {
// 无参数
@objc func reset() { }
// Selector: reset
// 单参数
@objc func add(_ value: Int) { }
// Selector: add:
// 多参数
@objc func add(_ a: Int, to b: Int) { }
// Selector: add:to:
// 自定义名称
@objc(calculateSumOf:and:)
func sum(_ a: Int, _ b: Int) -> Int { return a + b }
// Selector: calculateSumOf:and:
// 重载时需要类型注解
@objc func process(_ value: Int) { }
@objc func process(_ value: String) { }
func test() {
let intSelector = #selector(process(_:) as (Int) -> Void)
let stringSelector = #selector(process(_:) as (String) -> Void)
}
}

9.3 performSelector

class Handler: NSObject {
@objc func handleAction() {
print("Action handled")
}
@objc func handleAction(with param: String) {
print("Action: \(param)")
}
}
let handler = Handler()
// 无参数
handler.perform(#selector(Handler.handleAction))
// 带参数
handler.perform(#selector(Handler.handleAction(with:)), with: "test")
// 延迟执行
handler.perform(
#selector(Handler.handleAction),
with: nil,
afterDelay: 1.0
)
// 在指定线程执行
handler.performSelector(
onMainThread: #selector(Handler.handleAction),
with: nil,
waitUntilDone: false
)

十、高级混编技巧

10.1 Swift 调用 C/C++

// Swift 不能直接调用 C++,需要通过 OC 桥接
// 1. C 函数可以直接调用
// C header (MyCFunctions.h)
// int add(int a, int b);
// void processData(const char *data, size_t length);
// Bridging header
// #import "MyCFunctions.h"
// Swift
let result = add(1, 2)
let data = "Hello"
data.withCString { ptr in
processData(ptr, data.count)
}
// 2. C++ 需要 OC 包装
// CppWrapper.h
@interface CppWrapper : NSObject
- (void)processCpp:(NSString *)data;
@end
// CppWrapper.mm  (注意 .mm 扩展名)
#import "CppWrapper.h"
#include "MyCppClass.hpp"
@implementation CppWrapper {
MyCppClass *_cppObject;
}
- (instancetype)init {
self = [super init];
if (self) {
_cppObject = new MyCppClass();
}
return self;
}
- (void)dealloc {
delete _cppObject;
}
- (void)processCpp:(NSString *)data {
std::string cppString = [data UTF8String];
_cppObject->process(cppString);
}
@end
// Swift 使用
let wrapper = CppWrapper()
wrapper.processCpp("Hello C++")

10.2 运行时检查与反射

// Swift 对象的运行时检查
class MyClass: NSObject {
@objc dynamic var name: String = ""
@objc func doSomething() { }
}
// 1. 检查类和协议
let obj = MyClass()
if obj.isKind(of: MyClass.self) {
print("Is MyClass")
}
if obj.responds(to: #selector(MyClass.doSomething)) {
print("Responds to doSomething")
}
if obj.conforms(to: NSCopying.self) {
print("Conforms to NSCopying")
}
// 2. 获取类信息
let className = NSStringFromClass(type(of: obj))
print(className)  // _TtC8MyModule7MyClass
// 3. 动态方法调用
let selector = NSSelectorFromString("doSomething")
if obj.responds(to: selector) {
obj.perform(selector)
}
// 4. KVC
obj.setValue("Test", forKey: "name")
let value = obj.value(forKey: "name")
// 5. Mirror (Swift 反射)
let mirror = Mirror(reflecting: obj)
for child in mirror.children {
print("\(child.label ?? "?"): \(child.value)")
}

10.3 避免常见混编陷阱

// 陷阱 1: 可选值与 nil
class DataManager: NSObject {
// OC 返回 nil 时,Swift 必须处理
@objc func getData() -> NSData? {
return nil
}
}
// Swift 使用时需要解包
if let data = manager.getData() {
// 使用 data
}
// 陷阱 2: 集合类型元素
class Container: NSObject {
// OC 集合可以包含任意类型
@objc var items: NSMutableArray = []
}
// Swift 中需要类型转换
let container = Container()
container.items.add("string")
container.items.add(NSNumber(value: 42))
// 取出时需要转换
if let first = container.items.firstObject as? String {
print(first)
}
// 陷阱 3: 类型推断问题
// OC:
// @property (nonatomic, strong) id someObject;
// Swift 中是 Any,需要转换
let obj: Any = container.someObject
if let string = obj as? String {
// ...
}
// 陷阱 4: 初始化器
class SwiftClass: NSObject {
let requiredProperty: String
// 必须提供 @objc init
@objc init(property: String) {
self.requiredProperty = property
super.init()
}
// 如果有便利初始化器
@objc convenience init() {
self.init(property: "default")
}
}
// 陷阱 5: 闭包逃逸
class NetworkManager: NSObject {
// 必须标记 @escaping
@objc func request(completion: @escaping (Data?) -> Void) {
DispatchQueue.global().async {
completion(nil)
}
}
}

十一、性能优化建议

11.1 减少桥接开销

// 1. 批量处理而非逐个桥接
// ❌ 低效
func processOCItems(_ array: NSArray) {
for item in array {
if let str = item as? String {
// 每次循环都进行类型检查和转换
process(str)
}
}
}
// ✅ 高效
func processOCItems(_ array: NSArray) {
// 一次性转换
let swiftArray = array as? [String] ?? []
for str in swiftArray {
process(str)
}
}
// 2. 避免频繁的 String 桥接
// ❌ 频繁桥接
func appendToOCString(_ nsString: NSMutableString) {
for i in 0..<1000 {
nsString.append(String(i))  // 每次创建临时 String
}
}
// ✅ 使用 OC 原生方法
func appendToOCString(_ nsString: NSMutableString) {
for i in 0..<1000 {
nsString.append("\(i)" as NSString)  // 直接使用 NSString
}
}
// 3. 减少不必要的 @objc
class PureSwiftClass {
// 不需要 OC 互操作的类不要加 @objc
func internalMethod() { }
}

11.2 方法调度优化

// 1. 使用 final 减少动态调度
final class OptimizedManager {
func process() { }  // 静态调度
}
// 2. 使用 private 启用优化
class Manager {
private func helperMethod() { }  // 可被编译器优化
}
// 3. 最小化 @objc 范围
class ViewController: UIViewController {
// 只有需要 OC 交互的才用 @objc
@objc func handleButton() { }
// 纯 Swift 方法不用 @objc
func updateUI() { }
}
// 4. 避免不必要的 @objc dynamic
class ViewModel: NSObject {
// 需要 KVO 才用 dynamic
@objc dynamic var observableProperty: String = ""
// 不需要 KVO 就不用 dynamic
@objc var normalProperty: String = ""
}

十二、总结

12.1 混编核心要点

┌─────────────────────────────────────────────────────────────────────┐
│                    Swift/OC 混编核心要点                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│   【桥接文件】                                                       │
│   • xxx-Bridging-Header.h: Swift 访问 OC                           │
│   • xxx-Swift.h: OC 访问 Swift (自动生成)                          │
│                                                                      │
│   【@objc 相关】                                                     │
│   • @objc: 暴露给 OC 运行时                                        │
│   • @objcMembers: 批量暴露所有成员                                  │
│   • @objc dynamic: 启用完整的消息调度                               │
│   • @objc(name): 自定义 OC 中的名称                                │
│                                                                      │
│   【类型桥接】                                                       │
│   • String ⟷ NSString: 零开销                                     │
│   • Array ⟷ NSArray: 零开销                                       │
│   • Int ⟷ NSNumber: 需要装箱                                      │
│   • struct/enum: 不能直接桥接                                       │
│                                                                      │
│   【方法调度】                                                       │
│   • 静态调度: struct, final class, private                         │
│   • V-Table: class 普通方法                                        │
│   • 消息调度: @objc dynamic, NSObject 子类的 @objc 方法            │
│                                                                      │
│   【不能用 @objc】                                                   │
│   • 结构体、枚举(非Int)                                             │
│   • 泛型类型                                                        │
│   • 元组                                                            │
│   • 嵌套类型                                                        │
│   • Swift 独有特性 (默认参数等)                                     │
│                                                                      │
│   【性能建议】                                                       │
│   • 最小化 @objc 使用范围                                          │
│   • 批量桥接而非逐个                                                │
│   • 使用 final/private 启用优化                                    │
│   • 只在需要时使用 @objc dynamic                                   │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

12.2 最佳实践清单

□ 明确区分需要 OC 互操作和纯 Swift 的代码
□ 只在必要时使用 @objc,优先使用纯 Swift
□ 继承 NSObject 时考虑是否真的需要
□ 使用 final class 和 struct 优化性能
□ 正确处理可选值和类型转换
□ 闭包记得使用 [weak self] 或 [unowned self]
□ 理解三种方法调度方式及其适用场景
□ C++ 代码通过 OC 包装器暴露给 Swift
□ 合理使用协议:纯 Swift 协议 vs @objc 协议
□ 定期检查生成的 xxx-Swift.h 确保接口正确

参考资料

posted @ 2026-01-09 21:22  yangykaifa  阅读(6)  评论(0)    收藏  举报