显式解包可选类型nil为何未崩溃?如何禁用UITableViewCell选中高亮?
问题1:显式解包可选类型nil未导致崩溃,请问其原因是什么?
这种情况其实有几个常见场景,我给你逐一拆解:
编译器优化了无意义的解包操作:如果你显式解包后根本没实际使用这个值,比如写了这样的代码:
let opt: String! = nil let _ = opt! // 解包后未使用编译器可能会直接把这个解包操作优化掉,自然不会触发崩溃——毕竟崩溃的前提是你要访问nil的底层值,没用到的话就不会有内存访问错误。
与Objective-C交互的特殊桥接逻辑:有些Objective-C方法返回的
nullable对象,在Swift里会被桥接为隐式解包可选(IUO)。当你解包它并传递回Objective-C环境时,因为Objective-C本身允许nil值,Swift不会触发崩溃——相当于把nil又送回了能处理它的OC环境。解包Void类型的可选值:如果你的可选类型是
Optional<()>(也就是Void的可选类型),就算它是nil,显式解包x!得到的是空元组(),没有实际的内存访问操作,所以不会崩溃。这种情况比较特殊,但确实存在。自定义/第三方可选类型的特殊实现:如果是你自己定义的类似Optional的枚举,或者用了某些第三方库的包装类型,可能重写了解包逻辑,避免了崩溃。不过这种情况相对少见。
问题2:tableView(_:willSelectRowAt:)返回nil的具体限制是什么?
你用返回nil的方式禁用行高亮是完全没问题的,教程里提到的限制其实和这个方法的设计历史、Swift的类型规范有关:
iOS 13及更早版本的特殊允许:在iOS 13之前,这个方法的返回类型是
IndexPath!(隐式解包可选类型)。按照Swift的一般规则,返回IUO的方法通常期望你返回非nil值,因为调用者可能会直接解包使用。但willSelectRowAt是个特例——Apple专门允许在这里返回nil,用来明确表示「不允许选中这一行」。限制的核心:仅特定方法允许此操作:这个返回nil的行为是
willSelectRowAt(以及对应的willDeselectRowAt)这几个UITableViewDelegate方法特有的合法用法。对于其他返回IUO类型的方法,如果你随便返回nil,很可能会导致调用者解包时崩溃,因为那些方法的设计初衷是返回有效的实例。iOS 13之后的规范优化:从iOS 13开始,Apple把这个方法的返回类型改成了
IndexPath?(普通可选类型),这时候返回nil就完全符合Swift的可选类型设计了,不再需要特殊的“允许”说明——可选类型本身就支持返回nil。
简单说就是:不要把这个返回nil的逻辑套用到其他返回IUO的方法上,只有willSelectRowAt这类特定方法才被允许这么做来实现功能。
内容的提问来源于stack exchange,提问作者Martin Muldoon

