简单直接的回答是:不能直接访问,但可以通过“桥接”变通。
Objective-C 的底层架构(Runtime)是基于 C 语言指针和固定内存布局的,而 Swift 的 struct 和 enum(尤其是带关联值的)是现代值类型,其内存布局和管理方式与 OC 完全不兼容。
1. 为什么不能直接访问?(底层限制)
- 内存布局不透明:Swift
struct的大小在编译期决定,且不具备NSObject的头部信息(isa 指针)。OC 无法通过指针偏移量来安全地读取 Swift 结构体。 - 缺少 Runtime 元数据:OC 的方法调用依赖
objc_msgSend,它要求对象必须是类(Class)。struct和enum并不存在于 OC 的类列表中。 - 关联值的复杂性:Swift 的
enum可以携带任意类型的关联值,这在底层是“带标签的联合体”(Tagged Union),OC 没有任何语法能够表达这种结构。
2. 情况 A:Swift Enum(枚举)
只有一种情况可以访问:
如果你的 Swift 枚举是整型原始值(Integer Raw Value) ,且标记了 @objc,它会映射为 OC 的 NS_ENUM。
Swift
@objc enum UserRole: Int {
case admin, member, guest
}
- 映射结果:在
-Swift.h中,它会被翻译为typedef NS_ENUM(NSInteger, UserRole) { ... };。
无法访问的情况:
- 带关联值:
case success(String)这种无法映射。 - 字符串/浮点原始值:
enum Error: String无法直接映射。
3. 情况 B:Swift Struct(结构体)
完全无法直接访问。 即使你加了 @objc,编译器也会报错。
变通方案:包装器(Wrapper)
如果你必须在 OC 中使用 Swift 的 struct,最标准的做法是将其包装在一个继承自 NSObject 的类中。
Swift
struct User {
var name: String
var age: Int
}
@objc class UserWrapper: NSObject {
private var user: User
@objc var name: String { return user.name }
@objc var age: Int { return user.age }
init(user: User) {
self.user = user
}
}
4. 特殊桥接:C 语言结构体
如果你定义的不是 Swift struct 而是 C 语言结构体(在 Bridging-Header 中定义或在 Swift 中按 C 语法定义),那么两端都可以访问。但这种结构体无法拥有 Swift struct 的方法、计算属性等高级特性。
5. 总结对照表
| 类型 | 是否支持 OC 访问 | 限制条件 |
|---|---|---|
| Int 型 Enum | ✅ 支持 | 必须加 @objc,必须是 Int 原始值。 |
| String 型 Enum | ❌ 不支持 | OC 不支持字符串枚举,需用类常量替代。 |
| 带关联值 Enum | ❌ 不支持 | OC 无法理解内存布局。 |
| Swift Struct | ❌ 不支持 | 必须通过 Class 包装。 |
| C Struct | ✅ 支持 | 只能存储简单数据,无 Swift 逻辑。 |
💡 架构建议
在混编项目中,如果一个模型(Model)需要在两端频繁传递,建议将其定义为继承自 NSObject 的 Class。虽然会损失一些值类型的性能优势,但能极大地降低沟通成本和桥接代码的复杂性。