Swift控制流疑问:已做nil检查为什么强制解包还是遇到nil?
这不是Swift的bug,是你的代码逻辑存在问题,核心原因是你错误地使用了双重可选值,导致nil校验逻辑没有达到预期效果。
问题原因拆解
- 你在对字典取值做类型转换时,写了
as? String?和as? Date?,这会让internalId的类型变成**String??(双重可选值,即可选值的可选值)**,orderDate同理为Date??类型。 - 你的nil校验
if internalId == nil只会判断双重可选值的最外层是否为nil:只要字典中存在internalId这个key,哪怕对应的值本身是nil,外层可选值就不为nil,校验逻辑会判定为「有值」,不会走continue或fatalError分支。 - 举个实际场景:当
resultDict["internalId"]的取值本身是nil时,resultDict["internalId"] as? String?的结果是.some(nil),此时internalId == nil的判断结果为false,会正常进入后续逻辑,但你用!!做两次强制解包时,第一次解外层得到的是内层的nil,第二次解包就会触发强制解包nil的崩溃。
修复方案
最简单的修复是把类型转换的代码改为单层可选转换,去掉多余的?:
let internalId = resultDict["internalId"] as? String let orderDate = resultDict["orderDate"] as? Date
改完后原来的nil校验逻辑就可以正常生效,更推荐使用Swift官方推荐的可选绑定写法,完全避免强制解包:
for typelessResultDict in results { let resultDict = typelessResultDict as! Dictionary<String, Any> // 使用guard let一次性完成类型转换+非空校验 guard let internalId = resultDict["internalId"] as? String, let orderDate = resultDict["orderDate"] as? Date else { #if DEBUG fatalError("internalId/orderDate was nil") #endif continue } do { // 直接使用解包后的值,不需要再强制解包 try removeAllButOne(internalId: internalId, orderDate: orderDate) } catch { LOGGER.error("Could not deduplicate.") } }
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

