NSCoder decodeDouble необязательного значения

decodeDouble на NSCoder возвращает необязательное значение, но я хотел бы определить, было ли значение нулевым до того, как оно было закодировано.

Это мой сценарий:

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
}

Таким образом, декодирование double возвращает 0 в случае, если значение никогда не было установлено, поэтому кажется, что я не могу определить, было ли значение на самом деле 0 или nil до кодирования

Есть ли способ проверить, был ли двойник нулевым до того, как он был закодирован?


person MarkHim    schedule 24.11.2016    source источник
comment
вы можете преобразовать в NSNumber? для сохранения с помощью encodeObject и использовать decodeObject вместо decodeDouble   -  person Duyen-Hoa    schedule 24.11.2016
comment
Нужно ли уметь различать значение, закодированное значением nil, и значение, не существующее для ключа?   -  person Hamish    schedule 24.11.2016
comment
этот ответ полезен в вашем случае?   -  person Ahmad F    schedule 24.11.2016
comment
Хоа да, это то, что я делаю прямо сейчас. Но я подумал, что может быть более красивое решение. Hamish no, nil или not set может быть одинаковым. Ахмад, нет, потому что этот ответ не совсем правильный, так как пост-декодирование приводит к Swift? не изменяет необязательность - (приведение 0 к Double? все равно будет 0)   -  person MarkHim    schedule 24.11.2016


Ответы (1)


Решение состоит в том, чтобы использовать NSNumber вместо Double при кодировании, а затем использовать decodeObject, чтобы вернуть (если он существует) двойное значение. Например

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
        }
    }
}

По предложению @Hamish, вот версия для Swift 3. Имейте в виду, что нам нужно наследовать класс от NSObject, чтобы заставить работать NSEncoding (Получил нераспознанный селектор -replacementObjectForKeyedArchiver: сбой при реализации NSCoding в 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
    }
}
person Duyen-Hoa    schedule 24.11.2016
comment
Обратите внимание, что нет необходимости явно переходить через NSNumber — в Swift 3 простое указание aCoder.encode(optionalDouble, forKey: "myOptionalDouble") соединит Double с NSNumber, если optionalDouble не равно нулю. Вы также можете просто сказать as? Double в расшифровке. - person Hamish; 24.11.2016