Бросьте NSString! Строка в быстрой

У меня есть имя переменной экземпляра в String

var name: String

Мой класс реализует протокол NSCoding. Так что для имени у меня был

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

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

Результат? Во время инициирования с декодером я получал крах во время выполнения. Я изменил init на это:

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

и понял, что значение temp имеет правильное значение NSString. поэтому я подумал, что строка ниже собирается исправить это, но она выдает ошибку компоновщика:

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

вопросы: как взять temp и поместить его в имя?

Ответ 1

decodeObjectForKey возвращает необязательный AnyObject?, поэтому вам нужно защитить свой код от возможных значений nil. Использование броска для принудительной развертки не звучит безопасно.

Я не могу воспроизвести ошибку (так что проблема может быть где-то еще в вашем коде), но именно так я хотел бы при инициализации свойства name:

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

Обратите внимание на использование необязательного downcasting as?, который всегда производит результат (нуль или допустимое значение типа) в отличие от as NSString!, который запускает исключение, если нисходящее недоступно (например, если вы ожидая строку, но вместо нее вместо int).

Этот код также позволит вам лучше отлаживать - если tempName есть nil, то либо ключ не существует, либо соответствующее значение имеет другой тип.

Ответ 2

Мне нужно было сделать две вещи, чтобы заставить ее работать:

  • очистить сборку с удалением папки с производными данными
  • По какой-то причине переключение между NSString и String не работает в этой ситуации. поэтому литье должно выполняться в два этапа

    if let name = aDecoder.decodeObjectForKey(kName) as? NSString {
        self.name = name as String
    } else {
        assert(false, "ERROR: could not decode")
        self.name = "ERROR"
    }