Невозможно вызвать 'закодировать' со списком аргументов типа 'NSAttributedString' - PullRequest
0 голосов
/ 10 января 2019

Как я могу закодировать NSAttributedString и сохранить его на диске, используя UserDefaults?

Сначала я попытался установить протокол Codable:

class CoachProgram: Codable {
    var name: String
    var details: NSAttributedString
}

но компилятор выдает Type 'Coach' does not conform to protocol 'Encodable'. Итак, я начал реализовывать метод encode(to:):

public func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(details)
                  ^~~~~~ "error: cannot invoke 'encode' with an argument list of type '(NSAttributedString)'"
}

но безуспешно.

Моя идея состоит в том, чтобы использовать CoachProgram как:

let archiver = NSKeyedArchiver()
do {
    try archiver.encodeEncodable(coachProgram, forKey: NSKeyedArchiveRootObjectKey)
}
catch {
    print(error)
}
UserDefaults.standard.set(archiver.encodedData, forKey: "CoachProgram")

1 Ответ

0 голосов
/ 10 января 2019

Первая проблема: Я пытался использовать контейнер без ключей, и это не имеет смысла, потому что мне определенно нужен контейнер с ключами, потому что у меня есть 2 атрибута (name и details ** 1008).

Итак, мне нужно было реализовать некоторые CodingKey и использовать метод decoder.container(keyedBy:).

Вторая проблема: после некоторых экспериментов я заметил, что могу превратить NSAttributedString в Data, просто используя NSKeyedArchiver! Data - это Codable, поэтому я могу его кодировать и декодировать.

Итак, окончательное решение, которое я получил:

class CoachProgram: Codable {
    var name: String
    var details: NSAttributedString

    enum CodingKeys: String, CodingKey {
        case name
        case details
    }

    init(name: String, details: NSAttributedString) {
        self.name = name
        self.details = details
    }

    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let name = try container.decodeIfPresent(String.self, forKey: .name) {
            self.name = name
        }
        if let data = try container.decodeIfPresent(Data.self, forKey: .details) {
            self.details = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSAttributedString ?? NSAttributedString()
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(NSKeyedArchiver.archivedData(withRootObject: details), forKey: .details)
    }
}

В действии:

let coachProgram = CoachProgram(name: "John Doe", details: NSAttributedString())

let archiver = NSKeyedArchiver()
do {
    try archiver.encodeEncodable(coachProgram, forKey: NSKeyedArchiveRootObjectKey)
}
catch {
    print(error)
}
UserDefaults.standard.set(archiver.encodedData, forKey: "CoachProgram")
...