一张速查表先拎清
名称 | 具体类型 | 能容纳 | 典型场景 | Swift 版本 |
---|---|---|---|---|
Any | 顶层类型(具体类型) | 任意值(含函数、元组、struct、class) | 与旧 API 交互、极少数极端动态场景 | 1.0+ |
AnyObject | 协议(仅类/actor 遵循) | 引用类型(class / actor) | 弱引用容器、协议限制为引用语义 | 1.0+ |
any | existential 关键字 | 任意协议(含关联类型) | 声明"存在某个协议实现" | 5.7+ |
Any:万能口袋,但请少用
swift
let bag: [Any] = [
"Jack", // String
55, // Int
{ () -> Void in }, // 闭包
(44.9, 0) // 元组
]
问题:类型安全被"蒸发"
swift
struct StringValidator {
func validate(_ value: Any) -> Bool {
guard let str = value as? String else {
fatalError("只接受 String") // 运行时爆炸
}
return !str.isEmpty
}
}
更安全的替代
- 协议约束(推荐 1)
swift
protocol Validator {
associatedtype Value
func validate(_ value: Value) -> Bool
}
struct StringValidator: Validator {
typealias Value = String
func validate(_ value: String) -> Bool { !value.isEmpty }
}
- 泛型(推荐 2)
swift
struct AnyValidator<T>: Validator {
typealias Value = T
func validate(_ value: T) -> Bool {
if let str = value as? String { return !str.isEmpty }
if let int = value as? Int { return int > 0 }
return false
}
}
总结:能用协议/泛型就别用 Any。
AnyObject:只拥抱引用类型
- 只有
class
与actor
隐式遵循。 - 协议限制为"必须是引用类型"。
swift
protocol Cache: AnyObject {
func clear()
}
class MemoryCache: Cache {
func clear() { print("内存缓存清空") }
}
struct DiskCache: Cache { /* ❌ struct 无法遵守 AnyObject 协议 */ }
func perform(_ c: AnyObject) { /* 只接受引用类型 */ }
与 actor 搭配
swift
actor Counter {
private var value = 0
nonisolated func description() -> String { "CounterActor" }
}
let obj: AnyObject = Counter()
注意:
nonisolated
让 actor 方法同步调用,避免 await。
any:existential 关键字(Swift 5.7+)
- 用于 带关联类型的协议 或 需要运行时多态 时。
- 不是类型,而是标记:"这是一个盒子,里面装着某个具体实现"。
带关联类型的协议
swift
protocol AppleDevice {
associatedtype Chip
var chip: Chip { get }
}
class ModernMacBook: AppleDevice {
typealias Chip = String
let chip = "M3"
}
class OldMacBook: AppleDevice {
typealias Chip = Int
let chip = 42
}
// ✅ 正确:用 any 声明 existential
let devices: [any AppleDevice] = [ModernMacBook(), OldMacBook()]
// ❌ 错误:不能直接用协议名
// 使用协议类型,前面默认使用any修饰。目前会报警告,但后续会报错。需要明确写上any
// let wrong: [AppleDevice] = [ModernMacBook(), OldMacBook()]
与 some 的区别
关键字 | 含义 | 何时使用 |
---|---|---|
some | opaque type(编译期已知具体类型) | 返回值隐藏实现细节 |
any | existential(运行时才知道具体类型) | 参数、集合元素 |
swift
func opaque() -> some AppleDevice { ModernMacBook() } // 编译期确定
func existential(_ d: any AppleDevice) { ... } // 运行时多态
实战:弱引用容器场景
用 AnyObject 存储 delegate
swift
final class MulticastDelegate {
private var delegates = NSHashTable<AnyObject>.weakObjects()
func add<T: AnyObject>(_ delegate: T) {
delegates.add(delegate)
}
}
用 any 擦除带关联类型的协议
swift
protocol EventHandler {
associatedtype Event
func handle(_ event: Event)
}
struct AnyHandler<Event>: EventHandler {
private let _handle: (Event) -> Void
init<H: EventHandler>(_ handler: H) where H.Event == Event {
_handle = handler.handle
}
func handle(_ event: Event) { _handle(event) }
}
一句话总结
- Any ≈ 远古时代的
id
,能装万物,但类型信息全丢。 - AnyObject ≈ "必须是引用类型"的协议约束,常用于弱引用容器。
- any ≈ Swift 5.7 的新关键字,解决"带关联类型协议"的泛型多态问题。
开发口诀:能用具体类型 > 泛型 > 协议 > any > AnyObject > Any
按此优先级,你将获得类型安全、性能与可读性的三重保障。