cast NSString! to String in swift

Arash picture Arash · Sep 20, 2014 · Viewed 35.3k times · Source

I have a instance variable name in String

var name: String

My class implements the NSCoding protocol. So for name I had

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(self.name, forKey: kName)
}

required init(coder aDecoder: NSCoder) {
    self.name = aDecoder.decodeObjectForKey(kName) as String  // CRASH HERE
}

Result? I was getting a run time crash during initiation with decoder. I changed init to this:

var temp = aDecoder.decodeObjectForKey(kName) as NSString!
self.name = aDecoder.decodeObjectForKey(kName) as String

and realised the value temp is holding the right NSString value. so I thought the line below is going to fix it but it issues a linker error:

self.name = aDecoder.decodeObjectForKey(kName) as NSString!

the questions is how to take the temp and put it into name?

Answer

Antonio picture Antonio · Sep 20, 2014

decodeObjectForKey returns an optional AnyObject?, so you have to guard your code against possible nil values. Using a cast to a forced unwrapped doesn't sound safe.

I am unable to reproduce the error (so the problem could be somewhere else in your code), but this is how I would approach when initializing the name property:

    var tempName = aDecoder.decodeObjectForKey("name") as? String
    if let tempName = tempName {
        self.name = tempName
    } else {
        self.name = "some initial value"
    }

Note the usage of the optional downcasting as?, which always produce a result (nil or a valid type value) as opposed to as NSString!, which triggers an exception if the downcast is not possible (for instance if you are expecting a string, but it's an int instead).

That code would also allow you to better debugging - if tempName is nil, then either the key doesn't exist or the corresponding value is of a different type.