Swift 可选链

Swift 中的可选链(Optional Chaining) 是一种安全、简洁地访问可选值中的属性、方法、下标的机制。如果可选值为 nil,整个链式调用会优雅地返回 nil,而不会崩溃。


一、核心语法

optionalValue?.property
optionalValue?.method()
optionalValue?[index]

使用 ? 代替 .
如果 optionalValuenil → 整个表达式返回 nil
如果不是 nil → 继续访问


二、基础示例

class Person {
    var name: String
    var address: Address?

    init(name: String) {
        self.name = name
    }

    func greet() -> String {
        return "Hi, I'm \(name)"
    }
}

class Address {
    var street: String
    var city: String = "Beijing"

    init(street: String) {
        self.street = street
    }
}

let person: Person? = Person(name: "Alice")
person?.address = Address(street: "中关村大街1号")

// 安全访问
let city = person?.address?.city
print(city)  // Optional("Beijing")

// 如果 person 是 nil
let nobody: Person? = nil
let nobodyCity = nobody?.address?.city
print(nobodyCity)  // nil(不会崩溃)

三、可选链支持的操作

操作示例
属性访问person?.name
方法调用person?.greet()
下标访问array?.[0]
链式组合person?.address?.street?.uppercased()

四、完整链式调用示例

struct Book {
    var title: String
    var author: Author?
}

struct Author {
    var name: String
    var website: Website?
}

struct Website {
    var url: URL
    var isActive: Bool = true
}

// 构建数据
var book: Book? = Book(title: "Swift编程", author: Author(name: "张三", website: Website(url: URL(string: "https://example.com")!, isActive: true)))

// 可选链获取 URL 字符串
if let urlString = book?.author?.website?.url.absoluteString {
    print("作者网站: \(urlString)")
} else {
    print("无法获取网站")
}
// 输出: 作者网站: https://example.com

五、可选链 vs 传统解包

传统写法(繁琐)可选链(简洁)
if let p = person {
    if let a = p.address {
        if let c = a.city {
            print(c)
        }
    }
}

|

print(person?.address?.city)

|


六、可选链调用方法

class Player {
    func play() -> String { "播放中..." }
    func stop() { print("停止") }
}

let player: Player? = Player()

// 调用返回值的函数
let status = player?.play()
print(status)  // Optional("播放中...")

// 调用无返回值的函数
player?.stop()  // 如果 player 是 nil,什么都不发生

七、可选链 + 下标

let scores: [String: Int]? = ["Alice": 95, "Bob": 87]

let aliceScore = scores?["Alice"]
print(aliceScore)  // Optional(95)

let carolScore = scores?["Carol"]
print(carolScore)  // nil

八、可选链 + nil 合并运算符(常用组合)

let defaultCity = person?.address?.city ?? "未知城市"
print(defaultCity)  // 如果 city 为 nil,返回 "未知城市"

九、可选链设置属性(需注意)

只有在可选值非 nil 时才赋值

person?.address?.city = "Shanghai"  // 如果 person 或 address 是 nil,不会赋值

不会创建对象!仅在链条完整时生效


十、可选链与 if let 结合(高级)

if let city = person?.address?.city {
    print("住在: \(city)")
} else {
    print("地址信息不完整")
}

十一、可选链与 guard

func showWebsite(for book: Book?) {
    guard let url = book?.author?.website?.url else {
        print("无网站")
        return
    }
    print("打开: \(url)")
}

十二、可选链在实际项目中的应用

1. JSON 解析

let json: [String: Any]? = ["user": ["name": "李四", "profile": ["avatar": "url"]]]

let avatar = json?["user"] as? [String: Any]
                 ?["profile"] as? [String: Any]
                 ?["avatar"] as? String

print(avatar)  // Optional("url")

2. UI 控件安全访问

@IBOutlet weak var label: UILabel?

func updateUI() {
    label?.text = viewModel?.title?.uppercased()
    button?.isEnabled = viewModel?.isValid ?? false
}

十三、常见错误写法

错误写法正确写法
person!.name(强制解包,易崩溃)person?.name
person?.address.city(编译错误)person?.address?.city
array[0]?.name(下标在前)array?[0]?.name

最佳实践总结

场景推荐
访问嵌套可选属性?. 可选链
调用可选对象方法object?.method()
安全下标访问array?[index]
默认值??
提前返回guard let ... = x?.y?.z else { return }
避免强制解包 !除非 100% 确定非 nil

常见面试题

  1. 可选链返回什么类型?
    → 总是 Optional<T>
  2. 可选链中间某一步是 nil,后续会执行吗?
    → 不会,整个表达式返回 nil
  3. 可选链可以修改属性吗?
    → 可以,但只有链条完整时才生效
  4. 以下代码输出什么?
var str: String?? = "Hello"
print(str??.count)

Optional(5)

  1. 可选链和 if let 哪个性能更好?
    → 可选链更简洁,性能几乎无差别

小技巧

// 1. 可选链 + map(函数式)
let uppercased = person?.name.map { $0.uppercased() }

// 2. 可选链 + flatMap(压平嵌套可选)
let city = person?.address.flatMap { $0.city }

// 3. 安全调用协议方法
protocol Loggable {
    func log()
}
extension Optional where Wrapped: Loggable {
    func safeLog() {
        self?.log()
    }
}
optionalLogger?.safeLog()

高级话题(可继续提问)

  • 可选链与 KeyPath
  • 可选链在 SwiftUI 中的应用
  • 自定义可选链操作符
  • 编译器如何实现可选链(LLVM 层面)
  • 可选链与 @autoclosure 结合

需要完整 JSON 解析可选链实战SwiftUI 绑定示例,或性能测试对比?欢迎继续提问!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部