Могут ли NSCoding и Codable сосуществовать? - PullRequest
0 голосов
/ 07 июня 2018

При тестировании того, как новый Codable взаимодействует с NSCoding, я собрал игровой тест, включающий NSCoding с использованием Class, который содержит структуру Codable.К тому же

struct Unward: Codable {
    var id: Int
    var job: String
}

class Akward: NSObject, NSCoding {

    var name: String
    var more: Unward

    init(name: String, more: Unward) {
        self.name = name
        self.more = more
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(more, forKey: "more")
    }

    required init?(coder aDecoder: NSCoder) {
        name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        more = aDecoder.decodeObject(forKey: "more") as? Unward ?? Unward(id: -1, job: "unk")
        super.init()
    }
}

var upone = Unward(id: 12, job: "testing")
var adone = Akward(name: "Adrian", more: upone)

Вышеуказанное принимается игровой площадкой и не вызывает ошибок компилятора.

Если, однако, я пробую Saving adone, то так:

let encodeit = NSKeyedArchiver.archivedData(withRootObject: adone)

Детская площадка быстро падает с ошибкой:

ошибка: выполнение было прервано, причина: EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, субкод = 0x0).

Почему?Есть ли способ, чтобы класс NSCoding содержал Codable структуру?

1 Ответ

0 голосов
/ 08 июня 2018

Фактическая ошибка, которую вы получаете:

- [_ SwiftValue encodeWithCoder:]: нераспознанный селектор, отправленный экземпляру

И это исходит из строки:

aCoder.encode(more, forKey: "more")

Причина проблемы заключается в том, что more (типа Unward) не соответствует NSCoding.Но Swift struct не может соответствовать NSCoding.Вам нужно изменить Unward на класс, который расширяет NSObject в дополнение к соответствию NSCoding.Ничто из этого не влияет на способность соответствовать Codable.

Вот ваши обновленные классы:

class Unward: NSObject, Codable, NSCoding {
    var id: Int
    var job: String

    init(id: Int, job: String) {
        self.id = id
        self.job = job
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(id, forKey: "id")
        aCoder.encode(job, forKey: "job")
    }

    required init?(coder aDecoder: NSCoder) {
        id = aDecoder.decodeInteger(forKey: "id")
        job = aDecoder.decodeObject(forKey: "job") as? String ?? ""
    }
}

class Akward: NSObject, Codable, NSCoding {
    var name: String
    var more: Unward

    init(name: String, more: Unward) {
        self.name = name
        self.more = more
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(more, forKey: "more")
    }

    required init?(coder aDecoder: NSCoder) {
        name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        more = aDecoder.decodeObject(forKey: "more") as? Unward ?? Unward(id: -1, job: "unk")
    }
}

И ваши тестовые значения:

var upone = Unward(id: 12, job: "testing")
var adone = Akward(name: "Adrian", more: upone)

Теперь вы можетеархив и разархивирование:

let encodeit = NSKeyedArchiver.archivedData(withRootObject: adone)
let redone = NSKeyedUnarchiver.unarchiveObject(with: encodeit) as! Akward

И вы можете кодировать и декодировать:

let enc = try! JSONEncoder().encode(adone)
let dec = try! JSONDecoder().decode(Akward.self, from: enc)
...