MarkHim
MarkHim

Reputation: 5766

NSCoder decodeDouble of optional value

The decodeDouble on NSCoder returns a non-optional value, but I would like to identify whether a value was nil before it was encoded.

This is my scenario:

var optionalDouble: Double? = nil

func encode(with aCoder: NSCoder) {
    if let optionalDouble {
        aCoder.encode(optionalDouble, forKey: "myOptionalDouble")
    }
}

convenience required init?(coder aDecoder: NSCoder) {
    optionalDouble = aDecoder.decodeDouble(forKey: "myOptionalDouble") 
    // here optionalDouble is never nil anymore
}

So decoding double returns 0 in case the value was never set, so it seems like I can't identify whether a value was actually 0 or nil before encoding

Is there a way for me to check if a double was nil before it was encoded?

Upvotes: 3

Views: 1402

Answers (1)

Duyen-Hoa
Duyen-Hoa

Reputation: 15784

The solution is to use NSNumber instead of Double when you encode, then use decodeObject to get back (if it exists) the double value. For example

class A: NSCoding {
    var optionalDouble: Double? = nil

    @objc func encodeWithCoder(aCoder: NSCoder) {
        if let optionalDouble = optionalDouble {
            aCoder.encodeObject(NSNumber(double: optionalDouble), forKey: "myOptionalDouble")
        }
    }

    @objc required init?(coder aDecoder: NSCoder) {
        if let decodedDoubleNumber = aDecoder.decodeObjectForKey("myOptionalDouble") as? NSNumber {
            self.optionalDouble = decodedDoubleNumber.doubleValue
        } else {
            self.optionalDouble = nil
        }
    }
}

With suggestion from @Hamish, here is the version for Swift 3. Be aware that we need to inherit the class to NSObject in order to make NSEncoding work (Got Unrecognized selector -replacementObjectForKeyedArchiver: crash when implementing NSCoding in Swift)

class A: NSObject, NSCoding {
    var optionalDouble: Double? = nil

    func encode(with aCoder: NSCoder) {
        if let optionalDouble = optionalDouble {
            aCoder.encode(optionalDouble, forKey: "myOptionalDouble")
        }
    }

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        optionalDouble = aDecoder.decodeObject(forKey: "myOptionalDouble") as? Double
    }
}

Upvotes: 6

Related Questions