Swift中的Attributed String:带代码示例的完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Swift 中的感叹号:! 和 ? —— 背后隐藏着什么?



你是否曾看过别人的 Swift 代码,并在变量后面看到奇怪的感叹号?userName!、viewController!、self.label!.text! —— 然后疑惑:"他们为什么在喊叫?" 这个问题是 Stack Overflow 上最热门的问题之一(已有数万次浏览),今天我们将彻底把它讲清楚。



在这篇文章中,我们不会只说"这是强制解包"。我们将深入编译器内部,剖析 Swift 如何管理内存,并展示为什么感叹号既是你的好朋友,又是你最可怕的敌人。开始吧!



什么是可选类型(Optional),! 又从何而来?



在 Swift 中,任何变量都可以声明为可选。这意味着它可以包含一个值... 或者 nil(空值)。为什么?这样你的程序在没有数据时就不会崩溃。



看起来是这样的:



var name: String? = "Anna"   // 可选字符串var age: Int? = nil          // 也是可选,但为空


问号 ? 是 Optional<String> 的语法糖。也就是说,String? 实际上就是 Optional<String>。



现在来说重点:你不能直接使用可选变量。如果你试图写 print(name.count),编译器会报错。因为 name 里面可能含有 nil,而 nil 没有 count 属性。



这就是感叹号登场的地方。



! —— 这是强制解包



当你写 name! 时,你在告诉编译器:"我确定里面有值。直接给我,不用检查。" 编译器服从命令,从 Optional 盒子中取出值。



var name: String? = "Anna"print(name!) // 输出:Anna

var age: Int? = nilprint(age!) // 崩溃!致命错误:解包可选值时意外发现 nil


这就是为什么经验丰富的开发者不喜欢过度使用 !。如果你错了——程序就会崩溃。这就像是在和内存玩俄罗斯轮盘赌。



这在底层是如何工作的?



想象一下,Optional 是一个带锁的盒子。里面可能有一个值,也可能是空的。强制解包 就是你拿一根撬棍,不看一眼就直接把盒子砸开。如果里面是空的——你就把程序搞坏了。



在编译器内部,Optional 是一个枚举:



enum Optional<Wrapped> {    case none    // nil    case some(Wrapped)  // 值}


当你执行 name! 时,编译器生成的代码大致如下:



switch name {case .some(let value):    // 使用 valuecase .none:    fatalError("意外发现 nil")}


所以 ! 只是一个简写形式的 switch,带有 nil 检查,后面跟着 fatalError。



隐式解包可选类型 —— 类型中的 !



有时你会看到像 var label: UILabel! 这样的声明。这不是强制解包,而是隐式解包可选类型。你在说:"我保证这个变量会在首次使用之前被赋值,但现在它可以是 nil。"



var button: UIButton!  // 隐式解包可选类型

// 稍后...button = UIButton()button.setTitle("按下", for: .normal) // 无需 ! 即可工作


在底层,它仍然是同一个 Optional,但当你访问它时,编译器会自动插入一个强制解包。

博客

书籍推荐