iOS Swift 可选值(Optional)详解

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 中的 idNSString * 完全不同,是 编译器层面的安全保障


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 不是语法糖,而是 逼着你在代码层面提前思考风险

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

相关推荐
孟祥_成都2 小时前
nest.js / hono.js 一起学!日志功能/统一返回格式/错误处理
前端·node.js
_膨胀的大雄_2 小时前
01-创建型模式
前端·设计模式
小林rush2 小时前
uni-app跨分包自定义组件引用解决方案
前端·javascript·vue.js
我的一行2 小时前
已有项目,接入pnpm + turbo
前端·vue.js
亮子AI2 小时前
【Svelte】怎样实现一个图片上传功能?
开发语言·前端·javascript·svelte
心.c2 小时前
为什么在 Vue 3 中 uni.createCanvasContext 画不出图?
前端·javascript·vue.js
咸鱼加辣2 小时前
【vue面试】ref和reactive
前端·javascript·vue.js
LYFlied2 小时前
【每日算法】LeetCode 104. 二叉树的最大深度
前端·算法·leetcode·面试·职场和发展