Swift 与 Objective-C 最大的区别之一,就是 Optional(可选值)机制 。
它从语言层面解决了"空指针崩溃"的问题,但如果使用不当,也可能引入新的 Crash。
在日常开发中,我们经常看到下面这些写法:
swift
var name: String?
var age: Int!
let title = text ?? "默认标题"
imageView.image = UIImage(named: imgName ?? "")
本文将系统讲解 ?、!、?? 的含义、区别、适用场景与工程级最佳实践,帮助你在 Swift 项目中写出更安全、更专业的代码。
什么是 Optional(可选值)
在 Swift 中,Optional 表示一个变量「可能有值,也可能为 nil」。
swift
var name: String? = "Hello World"
name = nil
等价理解为:
「这个变量可以为空,编译器强制你在使用前处理好为空的情况」
这与 OC 中的 id、NSString * 完全不同,是 编译器层面的安全保障。
Optional 本质是什么?
从语言层面来看:
swift
let value: Int?
本质上相当于一个枚举:
swift
enum Optional<Int> {
case some(Int)
case none
}
也正是因为这样,Swift 不允许你直接使用 Optional 的值。
一、? ------ 可选类型(Optional)
定义方式
swift
var username: String?
表示:
- 可能有值
- 也可能为
nil
使用限制
swift
let len = username.count ❌ 编译错误
你必须 先解包(unwrap) ,才能使用。
安全解包方式一:if let
swift
if let name = username {
print(name.count)
} else {
print("username 为 nil")
}
安全解包方式二:guard let
swift
func printName(_ username: String?) {
guard let name = username else {
print("name 为 nil,提前返回")
return
}
print(name.count)
}
二、! ------ 强制解包(Force Unwrap)
定义方式
swift
var age: Int! = 18
表示:
"我确信这个变量在使用时一定不为 nil"
使用方式
swift
scss
print(age + 1) // 看起来像非 Optional
风险点
swift
age = nil
print(age + 1) // 运行时崩溃
"!"的正确使用场景
IBOutlet
生命周期受控变量
swift
@IBOutlet weak var titleLabel: UILabel!
原因:
- view 加载完成后一定存在
- 系统保证初始化时机
某些依赖注入后一定存在的对象
不推荐的用法
swift
var userName: String!
print(userName.count) // 非常危险 ❌
总结一句话:
!是写给"你未来的自己看的承诺",一旦违背就会 Crash
三、?? ------ 空值合并运算符(Nil-Coalescing)
基本用法
swift
let displayName = username ?? "匿名用户"
含义:
如果
username不为 nil,使用它否则使用
"匿名用户"
常见使用场景
场景 1:UI 显示兜底
swift
titleLabel.text = model.title ?? "暂无标题"
场景 2:参数默认值
swift
func loadData(page: Int?) {
let currentPage = page ?? 1
print(currentPage)
}
场景 3:Data / String 转换兜底
swift
let data = Data(base64Encoded: base64Str ?? "")
? + ?. ------ 可选链(Optional Chaining)
示例
swift
let length = username?.count
返回值类型:
swift
Int?
如果 username == nil:
- 不会执行
.count - 整个表达式返回 nil
常见链式调用
swift
let city = user?.profile?.address?.city
从服务器返回数据解析
swift
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) 岁")
}
常见错误用法总结
滥用 !
swift
user!.name!.count ❌
嵌套 if let 过深
swift
if let a = a {
if let b = b {
if let c = c {
...
}
}
}
更优写法:
swift
guard let a, let b, let c else { return }
总结
Swift 的 Optional 不是语法糖,而是 逼着你在代码层面提前思考风险。
如有说错的地方,满发指正相互学习,谢谢~