Buri
Buri

Reputation: 48

Swift: Comparing Implicitly Unwrapped Optionals results in "unexpectedly found nil while unwrapping an Optional values"

If got this class and would like to compare instances of it based on the value

class LocationOption: NSObject {
  var name:String!
  var radius:Int!
  var value:String!

  override func isEqual(object: AnyObject?) -> Bool {
    if let otherOption = object as? LocationOption {
        return (self.name == otherOption.name) &&
            (self.radius == otherOption.radius) &&
            (self.value == otherOption.value)
    }
    return false
  }
}

When executing this:

var a = LocationOption()
var b = LocationOption()

a.name = "test"
b.name = "test"

if a == b {  // Crashes here!!
  print("a and b are the same");
}

This crashes with "unexpectedly found nil while unwrapping an Optional value"? You can copy all this into a Playground to reproduce.

It seems to be due to the Implicitly Unwrapped Optionals. If I declare all fields as Optionals it works as expected.

But in my case, I would like to have these properties as Implicitly Unwrapped Optionals. How should I write the isEqual?

===

UPDATE: @matt is right and as I didn't want to change to "regular" Optionals I ended up with this:

class LocationOption: Equatable {
    var name:String!
    var requireGps:Bool!
    var radius:Int!
    var value:String!
}

func ==(lhs: LocationOption, rhs: LocationOption) -> Bool {
    let ln:String? = lhs.name as String?, rn = rhs.name  as String?
    let lr = lhs.radius as Int?, rr = rhs.radius as Int?
    return ln == rn && lr == rr
}

Upvotes: 2

Views: 283

Answers (1)

matt
matt

Reputation: 535851

You can't unwrap nil. That Is The Law. You can't get around this law merely by using implicitly unwrapped Optionals. Your implicitly unwrapped optionals are still Optionals. So when your test refers to self.radius and self.value and you have not set them, they are nil. So you are trying to unwrap nil and you crash.

In fact, your use if implicitly unwrapped Optionals makes things worse. When you declare them as normal Optionals, they are not implicitly unwrapped and so they are not unwrapped at all — comparing normal Optionals with the == operator is safe, because the compiler inserts a nil test for you. Thus The Law is never violated. But you have thrown away that safety by making these implicitly unwrapped Optionals. That is what the exclamation marks means; it means you can crash. If you don't want that to happen then:

  • Don't do that. Or:

  • Insert an explicit test for nil, yourself.

Upvotes: 4

Related Questions