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 <SomeFramework/SomeFramework.h>                     │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                           │                                          │
│                           ▼                                          │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  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 模块化与混编

swift 复制代码
// 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 的作用

swift 复制代码
// @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 批量暴露

swift 复制代码
// @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 的限制

swift 复制代码
// 以下类型不能用 @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 的必要性

swift 复制代码
// 场景:需要 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 零开销桥接原理

swift 复制代码
// 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 装箱类型的开销

swift 复制代码
// 值类型到 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 自定义类型桥接

swift 复制代码
// 通过 _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 复制代码
// 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 类型

swift 复制代码
// 处理手动内存管理的 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

swift 复制代码
// 可以被 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

swift 复制代码
// 协议扩展的方法对 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 复制代码
// 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 轻量泛型

objc 复制代码
// 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 复制代码
// 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 方法的错误处理

swift 复制代码
// 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 的使用

swift 复制代码
// #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 命名

swift 复制代码
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

swift 复制代码
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 复制代码
// 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 复制代码
// 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 避免常见混编陷阱

swift 复制代码
// 陷阱 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 减少桥接开销

swift 复制代码
// 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 方法调度优化

swift 复制代码
// 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 确保接口正确

参考资料

相关推荐
游戏开发爱好者83 小时前
以 uni-app 为核心的 iOS 上架流程实践, 从构建到最终提交的完整路径
android·ios·小程序·https·uni-app·iphone·webview
Sheffi664 小时前
iOS 内存分配机制:Malloc、VM、Dirty Memory
macos·ios·cocoa
游戏开发爱好者84 小时前
构建可落地的 iOS 性能测试体系,从场景拆解到多工具协同的工程化实践
android·ios·小程序·https·uni-app·iphone·webview
东坡肘子4 小时前
挖掘“沉默的专家” -- 肘子的 Swift 周报 #114
人工智能·swiftui·swift
sweet丶12 小时前
理解iOS中Protobuf:一个比JSON更好,但不是替代
ios·性能优化·架构
疯笔码良21 小时前
【IOS开发】Instruments 使用指南
ios·swift
疯笔码良1 天前
【IOS开发】后台保活方案
ios·swift
吴Wu涛涛涛涛涛Tao1 天前
从单体到子壳:一套「对标亿级 DAU App」的 iOS 架构实战 Demo
ios·架构
linweidong1 天前
网易ios面试题及参考答案(上)
ios·cdn·进程状态·虚拟内存·raii·网络链路·dns系统