Swift control flow: Unwrapping nil despite if check?

Nicolas

This sounds like a programming-newbie-question but how is this situation possible?

enter image description here

for typelessResultDict in results {
    let resultDict = typelessResultDict as! Dictionary<String, Any>
    let internalId = resultDict["internalId"] as? String?
    let orderDate = resultDict["orderDate"] as? Date?
    
    if internalId == nil || orderDate == nil {
        #if DEBUG
        fatalError("internalId/orderDate was nil")
        #endif
        continue
    }
    do {
        try removeAllButOne(internalId: internalId!!, orderDate: orderDate!!)
    } catch {
        LOGGER.error("Could not deduplicate.")
    }
}

In a for loop, I am explicitly checking if the variable orderDate is nil and either raise a fatalError in DEBUG or at least continue the loop, effectively canceling all other statements.

However, you can see that my code is executed and raises a fatal error because of force-unwrapping nil a few lines later.

Is this a bug or do I need to revisit first semester computer science?

Sweeper

Note that the types of internalId and orderDate are double optionals - String?? and Date?? respectively. This happens because resultDict["internalId"] produces a Any? (the key could be absent in the dictionary), and the safe cast to String? produces a String??, as there are 3 cases:

  • the key is present in the dictionary, and the cast succeeds (both layers of optional would be non-nil)
  • the key is absent in the dictionary (the outer optional would be non-nil, wrapping a nil as the inner optional)
  • the cast fails (the outer optional is nil)

== nil only checks if the outermost layer of the optional is nil, but you are unwrapping both layers with two exclamation marks. The first exclamation mark is safe as ensured by your if statement, but the second is not.

You can avoid all of this if you just cast to String and Date instead:

let internalId = resultDict["internalId"] as? String
let orderDate = resultDict["orderDate"] as? Date

You can also use a guard statement to eliminate the forced unwrapping:

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.")
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

swift syntax, check for nil before unwrapping

Is there an inline nil check for optional string values in swift while unwrapping?

NSCalendar initialisation unwrapping to nil, Swift

Unwrapping Json Swift (found nil)

using guard to check for nil without implicitly unwrapping

unexpectedly found nil while unwrapping an Optional value DESPITE checking

found nil while unwrapping optional in Swift

Swift - nil when unwrapping option value on for loop

Swift error unwrapping nil from Nib in viewDidLoad

Why is 'Fatal error: Unexpectedly found nil while unwrapping an Optional value' showing despite no nil values being present?

Swift control flow:

Swift control flow

Swift control flow with stride

Unexpectedly found nil while unwrapping optional value (Swift, Parse)

fatal error: unexpectedly found nil while unwrapping an Optional value swift

Swift 4 adding annotations error unexpectedly found nil while unwrapping

Swift: error: Unexpectedly found nil while implicitly unwrapping an Optional value

Unexpectedly found nil while unwrapping an Optional value swift

Swift: UIImageView - Unexpectedly found nil while unwrapping an Optional value

Swift why unwrapping optional by guarding against NIL is not working

Swift unit test - unexpectedly found nil while unwrapping an Optional value

Swift issue with nil found while unwrapping an Optional value NSDefautlts

Swift: “unexpectedly found nil while unwrapping an Optional value” in array append

Unexpectedly found nil while unwrapping an Optional value in Json parsing in swift

Swift Gyroscope: Unexpectedly found nil while unwrapping an Optional value

Swift unexpectedly found nil while unwrapping an optional value

Swift - Error: unexpectedly found nil while unwrapping an optional value

Swift Data Model returning nil after unwrapping when there clearly is value

Swift addGestureRecognizer: Unexpectedly found nil while unwrapping an Optional value