У меня проблемы с приведенным ниже кодом в Swift. Я извлек код из одного из своих приложений и настроил игровую площадку, чтобы проверить его поведение.
Иногда следующая строка выполняется успешно, а иногда нет:
if var selectedCards = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [Account : Card] {
Ничего не меняется между запусками на игровой площадке.
Если бы кто-нибудь мог мне помочь, это было бы очень признательно. Это сводит меня с ума!
Когда линия выходит из строя на игровой площадке, она завершается ошибкой ниже:
Выполнение было прервано, причина: EXC_BAD_INSTRUCTION (код=EXC_I386_INVOP, субкод=0x0
Когда строка терпит неудачу в моем приложении, она завершается с той же ошибкой, и это печатается в консоли отладки:
фатальная ошибка: неожиданно найдено nil при развертывании необязательного значения
Игровая площадка
import Foundation
Класс аккаунта
class Account: NSObject, Comparable, NSCoding, NSCopying {
var email: String = ""
var locked: Bool = false
override var hashValue: Int {
return email.hash
}
required init(email: String) {
super.init()
self.email = email
self.locked = false
}
required init?(coder decoder: NSCoder) {
email = decoder.decodeObjectForKey("email") as! String
locked = decoder.decodeBoolForKey("locked")
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(email, forKey: "email")
coder.encodeBool(locked, forKey: "locked")
}
func copyWithZone(zone: NSZone) -> AnyObject {
let account = self.dynamicType.init(email: self.email)
account.email = self.email
account.locked = self.locked
return account
}
override func isEqual(object: AnyObject?) -> Bool {
guard let account = object as? Account else { return false }
return account == self
}
}
func ==(lhs: Account, rhs: Account) -> Bool {
let emailEqual = lhs.email == rhs.email
return emailEqual
}
func <(lhs: Account, rhs: Account) -> Bool {
return lhs.email < rhs.email
}
Класс карты
class Card: NSObject, Comparable, NSCoding {
var id: String = ""
var name: String = ""
override var hashValue: Int {
return id.hash
}
init(id: String, name: String) {
super.init()
self.id = id
self.name = name
}
required init?(coder decoder: NSCoder) {
id = decoder.decodeObjectForKey("id") as! String
name = decoder.decodeObjectForKey("name") as! String
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(id, forKey: "id")
coder.encodeObject(name, forKey: "name")
}
override func isEqual(object: AnyObject?) -> Bool {
guard let card = object as? Card else { return false }
return card == self
}
}
func ==(lhs: Card, rhs: Card) -> Bool {
let idEqual = lhs.id == rhs.id
let nameEqual = lhs.name == rhs.name
return idEqual && nameEqual
}
func <(lhs: Card, rhs: Card) -> Bool {
if lhs.name == rhs.name {
return lhs.id < rhs.id
}
return lhs.name < rhs.name
}
Тест
let account = Account(email: "[email protected]")
let card = Card(id: "1", name: "Card 1")
let map: [Account : Card] = [account : card]
let data = NSKeyedArchiver.archivedDataWithRootObject(map)
if var selectedCards = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [Account : Card] {
let selectedCard = Card(id: "2", name: "Card 2")
selectedCards[account] = selectedCard
print("Success")
}
... as? [Account: Card]
: взгляните на требуемые неудачные инициализаторы для этих двух классов, например. принудительное преобразование типовemail = ... as! String
иid = ... as! String
. Они не дадут сбой и не вернутnil
в случае, если декодер (например, для ключа"id"
) выдастnil
до принудительного приведения (as
), а, скорее, произойдет сбой. Попробуйте переписать эти инициализаторы, используя безопасную распаковку декодирования объекта (например, необязательную привязку), возвращаяnil
в случае сбоя декодирования (следовательно, сбой инициализации, а не ее сбой). - person dfrib   schedule 15.04.2016NSKeyedArchiver
здесь не имеет значения, так как мы можем свести ту же проблему к явной попытке создатьNSDictionary
как[account: card]
, то естьlet map: NSDictionary = [account : card]
(или просто[account: "foo"]
). Это также время от времени дает сбой с фатальной ошибкой неожиданно найдено nil при развертывании необязательного значения. Естественно,NSDictionary
не может содержать ключи, равныеnil
, но я не могу объяснить, почемуaccount
недетерминированно даетnil
при вводе в качестве ключа/значения вNSDictionary
. Этот вопрос и ответ кажется связанным. - person dfrib   schedule 15.04.2016