iOS Swift 可选值(Optional)详解

19 阅读3分钟

Swift 与 Objective-C 最大的区别之一,就是 Optional(可选值)机制
它从语言层面解决了“空指针崩溃”的问题,但如果使用不当,也可能引入新的 Crash。

在日常开发中,我们经常看到下面这些写法:

var name: String?
var age: Int!

let title = text ?? "默认标题"
imageView.image = UIImage(named: imgName ?? "")

本文将系统讲解 ?!?? 的含义、区别、适用场景与工程级最佳实践,帮助你在 Swift 项目中写出更安全、更专业的代码。


什么是 Optional(可选值)

在 Swift 中,Optional 表示一个变量「可能有值,也可能为 nil」

var name: String? = "Hello World"
name = nil

等价理解为:

「这个变量可以为空,编译器强制你在使用前处理好为空的情况」

这与 OC 中的 idNSString * 完全不同,是 编译器层面的安全保障


Optional 本质是什么?

从语言层面来看:

let value: Int?

本质上相当于一个枚举:

enum Optional<Int> {
    case some(Int)
    case none
}

也正是因为这样,Swift 不允许你直接使用 Optional 的值


一、? —— 可选类型(Optional)

定义方式

var username: String?

表示:

  • 可能有值
  • 也可能为 nil

使用限制

let len = username.count  编译错误

你必须 先解包(unwrap) ,才能使用。


安全解包方式一:if let

if let name = username {
    print(name.count)
} else {
    print("username 为 nil")
}

安全解包方式二:guard let

func printName(_ username: String?) {
    guard let name = username else {
        print("name 为 nil,提前返回")
        return
    }
    
    print(name.count)
}

二、! —— 强制解包(Force Unwrap)

定义方式

var age: Int! = 18

表示:

“我确信这个变量在使用时一定不为 nil”


使用方式

swift

print(age + 1)   // 看起来像非 Optional

风险点

age = nil
print(age + 1)  // 运行时崩溃

"!"的正确使用场景

IBOutlet
生命周期受控变量

@IBOutlet weak var titleLabel: UILabel!

原因:

  • view 加载完成后一定存在
  • 系统保证初始化时机

某些依赖注入后一定存在的对象


不推荐的用法

var userName: String!
print(userName.count) // 非常危险 ❌

总结一句话

! 是写给“你未来的自己看的承诺”,一旦违背就会 Crash


三、?? —— 空值合并运算符(Nil-Coalescing)

基本用法

let displayName = username ?? "匿名用户"

含义:

如果 username 不为 nil,使用它
否则使用 "匿名用户"


常见使用场景

场景 1:UI 显示兜底

titleLabel.text = model.title ?? "暂无标题"

场景 2:参数默认值

func loadData(page: Int?) {
    let currentPage = page ?? 1
    print(currentPage)
}

场景 3:Data / String 转换兜底

let data = Data(base64Encoded: base64Str ?? "")

? + ?. —— 可选链(Optional Chaining)

示例

let length = username?.count

返回值类型:

Int?

如果 username == nil

  • 不会执行 .count
  • 整个表达式返回 nil

常见链式调用

let city = user?.profile?.address?.city

从服务器返回数据解析

struct User {
    let name: String?
    let age: Int?
}

func showUser(_ user: User?) {
    guard let user else {
        print("user 不存在")
        return
    }
    
    let name = user.name ?? "未知"
    let age = user.age ?? 0
    
    print("(name),(age) 岁")
}

常见错误用法总结

滥用 !

user!.name!.count 

嵌套 if let 过深

if let a = a {
    if let b = b {
        if let c = c {
            ...
        }
    }
}

更优写法:

guard let a, let b, let c else { return }

总结

Swift 的 Optional 不是语法糖,而是 逼着你在代码层面提前思考风险

如有说错的地方,满发指正相互学习,谢谢~