How do I get an optional from decodeIntegerForKey instead of 0?
Asked Answered
C

3

7

My app saves settings to a file on an iOS device by archiving instances of a class with properties. The class uses the NSCoding protocol, and therefore, I encode these properties using encodeWithCoder. I then try to read these files back into memory using a command such as tempInt = decoder.decodeIntegerForKey("profileFlags") as Int

This has worked well so far, but now I need to be able to store additional properties and retrieve them. In essence, the structure of this archived object is being changed, but users will already have files with the old structure (which has fewer properties). If the user has a file with the new structure (additional properties), then I want to read them. If not, I want to be able to execute code to handle that and provide default values.

I tried using a nonexistent key tempInt = decoder.decodeIntegerForKey("nonExistentKey") as Int, expecting to get a nil value, but it returned a zero. Unfortunately, this is one place where I really need an optional, because 0 is a valid value.

The closest help article I can find is Swift: decodeObjectForKey crashes if key doesn't exist but that doesn't seem to apply here. It seems like decodeObjectForKey returns an optional and decodeIntegerForKey returns an Integer.

Any ideas on how to do this?

Casa answered 9/9, 2015 at 23:11 Comment(0)
T
11

You can check using decoder.containsValueForKey("nonExistentKey") wether or not there is an actual value present and only if it is extract it with decodeIntegerForKey:

if decoder.containsValueForKey("nonExistentKey") {
    let tempInt = decoder.decodeIntegerForKey("nonExistentKey") 
}
Transport answered 9/9, 2015 at 23:17 Comment(1)
"If the encoded integer does not fit into the default integer size, the method raises an NSRangeException." Unfortunately it's hard to handle that in Swift.Naamana
C
2

You can use decodeObjectForKey that returns nil instead of zero. You just need to downcast to Int as follow:

decoder.decodeObjectForKey("profileFlags") as? Int
Chandler answered 10/9, 2015 at 0:45 Comment(0)
L
0

@luk2302 gave you the answer, but I wanted to adjust the syntax slightly and expand on it:

var tempInt: Int? 
let key = "profileFlags"
let hasValue = decoder.containsValueForKey(key)
tempInt = hasValue ? decoder.decodeIntegerForKey(key) : nil

The last statement is using the "tertiary operator", which has the same effect as:

if hasValue
{
  tempInt = decoder.decodeIntegerForKey(key)
}
else
{
  tempInt = nil
}

...but all in 1 line. It's a little odd-looking until you get used to it, but it is a very concise way to express this sort of thing.

Lasagne answered 9/9, 2015 at 23:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.