SwiftUI - пытается создать кодируемые перечисления, но появляется ошибка: «Generi c параметр 'S' не может быть выведен» - PullRequest
0 голосов
/ 06 февраля 2020

Я пытаюсь сделать перечисление ParentalSalary соответствующим Codable, чтобы его можно было сохранить в UserDefaults. Я попытался следовать этому руководству: https://blog.natanrolnik.me/codable-enums-associated-values и настроил его в соответствии с моей программой.

Кроме того, я застрял в устранении неполадок, так как не могу найти никаких решений / объяснений при поиске сообщения об ошибке.

Ниже приведен код перечисления, которое я пытаясь создать Codable:

enum ParentalSalary {
    case noSalary
    case upTo(percentage: Int)
}

extension ParentalSalary : Codable {

    private enum CodingKeys: String, CodingKey {
        case typeOfSalary
        case percentage
    }

    private enum TypeOfSalaryCodingKeys : String, Codable {
        case noSalary
        case upTo
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
            case .noSalary:
                try container.encode(TypeOfSalaryCodingKeys.noSalary, forKey: .typeOfSalary)
            case .upTo(let percentage):
                try container.encode(TypeOfSalaryCodingKeys.upTo, forKey: .typeOfSalary)
                try container.encode(percentage, forKey: .percentage)
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let typeOfSalary = try container.decode(ParentalSalary.self, forKey: .typeOfSalary)

        switch typeOfSalary {
            case .noSalary:
                self = .noSalary
            case .upTo:
                let percentage = try container.decode(Int.self, forKey: .percentage)
                self = .upTo(percentage: percentage)
        }
    }
}

Кроме того, я использую тип данных ParentalSalary в отдельной структуре (Profile: Identifiable, Codable), которую я, в свою очередь, создаю ObservableObject и сохраняю в UserDefaults используя JSONEncoder() и JSONDecoder(). См. Ниже:

class TheProfile: ObservableObject {
    @Published var profile = Profile.default{
    didSet {
        let encoder = JSONEncoder()
        if let encoded = try? encoder.encode(profile) {
            UserDefaults.standard.set(encoded, forKey: "Profile")
            }
        }
    }
    init() {
        if let profile = UserDefaults.standard.data(forKey: "Profile") {
            let decoder = JSONDecoder()
            if let decoded = try? decoder.decode(Profile.self, from: profile) {
                self.profile = decoded
                return
            }
        }

        self.profile = Profile.default
    }
}

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

Generi c параметр 'S' не может быть выведен

Я делаю ошибку в перечислении ParentalSalary в том смысле, что он не соответствует Codable или это вызвано какой-то другой причиной?

Одно подозрение, которое у меня возникло (в связи с тем, что я только что узнал об этом), заключается в том, что может возникнуть проблема с кодированием Profile: Identifiable, Codable с помощью JSONEncoder() в сочетании с кодированием перечисления ParentalSalary другим (? ) кодировщик.

Любой вход или поддержка очень ценится.

1 Ответ

1 голос
/ 07 февраля 2020

Проблема в вашем методе декодирования. Вам необходимо сначала декодировать вашу typeOfSalary клавишу, которая является String, переключить декодированный String и декодировать процент в случае, если он равен TypeOfSalaryCodingKeys.upTo.rawValue:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let typeOfSalary = try container.decode(String.self, forKey: .typeOfSalary)
    switch typeOfSalary {
    case TypeOfSalaryCodingKeys.noSalary.rawValue:
        self = .noSalary
    case TypeOfSalaryCodingKeys.upTo.rawValue:
        self = .upTo(percentage: try container.decode(Int.self, forKey: .percentage))
    default:
        throw DecodingError.dataCorruptedError(forKey: CodingKeys.typeOfSalary, in: container, debugDescription: "Invalid Type of Salary: \(typeOfSalary)")
    }
}

Тестирование игровой площадки:

let ps1: ParentalSalary = .noSalary
let ps2: ParentalSalary = .upTo(percentage: 27)
let parentalSalaries: [ParentalSalary] = [ps1,ps2]

do {
    let psData = try JSONEncoder().encode(parentalSalaries)
    print(String(data: psData, encoding: .utf8)!)
    let loadedJSON = try JSONDecoder().decode([ParentalSalary].self, from: psData)
    print(loadedJSON)
} catch {
    print(error)
}

Будет напечатано:

[{"typeOfSalary": "noSalary"}, {"typeOfSalary": "upTo", "процент": 27} ] [__lldb_expr_1.ParentalSalary.noSalary, __lldb_expr_1.ParentalSalary.upTo (в процентах: 27)]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...