彻底搞懂 Swift 的 Any、AnyObject、any

一张速查表先拎清

名称 具体类型 能容纳 典型场景 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:只拥抱引用类型

  • 只有 classactor 隐式遵循。
  • 协议限制为"必须是引用类型"。
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

按此优先级,你将获得类型安全、性能与可读性的三重保障。

相关推荐
如此风景20 小时前
Swift异步详解
swift
HarderCoder21 小时前
强制 SwiftUI 重新渲染:`.id()` 这把“重启键”你用对了吗?
swift
HarderCoder21 小时前
Swift 6.2 新语法糖:在字符串插值里直接给 Optional 写默认值
swift
HarderCoder1 天前
窥探 `@Observable` 的“小黑盒”:private 属性到底会不会被观察?
swift
zzywxc7871 天前
AI 在金融、医疗、教育、制造业等领域有着广泛的应用,以下是这些领域的一些落地案例
人工智能·python·spring cloud·金融·swift·空间计算
HarderCoder1 天前
Swift 并发避坑指南:自己动手实现“原子”属性与集合
swift
HarderCoder1 天前
惊!只是 `import Foundation`,`String.contains("")` 的返回值居然变了?
swift
HarderCoder1 天前
Swift 6.2 新武器:`weak let` —— 既弱引用又不可变的安全魔法
swift
HarderCoder1 天前
吃透 Swift 的 `@autoclosure`:把“表达式”变“闭包”的延迟利器
swift
HarderCoder2 天前
@Observable 遇上属性包装器:一键绕过‘计算属性’禁令的 Swift 5.9 实战技巧
swift