Type 'Self.Type' cannot conform to 'Decodable'

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Type 'Self.Type' cannot conform to 'Decodable'

    Hallo,

    ich habe schon wieder ein Problem.
    Ich will ein Protocol mit einer Standard-Implementierung zum lesen und speichern von UserDefaults erstellen.
    Ich stolpere jedoch über den Type für den JSONDecoder. Die Fehlermeldung lautet: Type 'Self.Type' cannot conform to 'Decodable'
    Wo ist mein Fehler?

    Quellcode

    1. import Foundation
    2. import CryptoKit
    3. public protocol UserDefault: Codable {
    4. static var key: String { get }
    5. static func getUserDefault(_ key: String, default: Bool) -> Self.Type
    6. func setUserDefault(_ key: String)
    7. }
    8. /// Extension to implement a default for `UserDefault`.
    9. extension UserDefault {
    10. static func getUserDefault() -> Self.Type? {
    11. if let asSealedBox = UserDefaults.standard.object(forKey: Self.key) as? ChaChaPoly.SealedBox,
    12. let asString = Crypto.encrypt(asSealedBox),
    13. let asData = asString.data(using: .utf8) {
    14. return try! JSONDecoder().decode(Self.Type, from: asData)
    15. } else {
    16. return nil
    17. }
    18. }
    19. func setUserDefault(_ key: String) {
    20. if let asData = try? JSONEncoder().encode(self),
    21. let asString = String(data: asData, encoding: String.Encoding.utf8),
    22. let asSealedBox = Crypto.decrypt(asString) {
    23. UserDefaults.standard.set(asSealedBox, forKey: key)
    24. }
    25. }
    26. }
    Alles anzeigen
  • MyMattes schrieb:

    Statt Deine Frage zu beantworten, eine Gegenfrage: Sollte man zum Speichern von vertraulichen Informationen nicht eher die Keychain als ein verschlüsseltes JSON in den UserDefaults nutzen? Warum machst Du das?

    Mattes
    Ich will nur die Configuration der App in den UserDefaults speichern.
    Da diese auch eine Password Policy enthält, wollte ich sie verschlüsseln.
  • Jetzt mal abgesehen von den angesprochenen Bedenken von Wolf und Mattes, versuche ich auf deine Urprungsfrage einzugehen.

    Heruhaundo schrieb:

    Die Fehlermeldung lautet: Type 'Self.Type' cannot conform to 'Decodable'
    Habe deinen Code jetzt nicht ausprobiert, aber augenscheinlich ist es genau das, was die Fehlermeldung besagt. Ich glaube deine Protokoll-Deklaration ist falsch:

    Quellcode

    1. public protocol UserDefault: Codable {
    2. ...
    3. static func getUserDefault(_ key: String, default: Bool) -> Self.Type
    4. ...
    5. }
    Warum ist der Rückgabe-Typ hier denn Self.Type? Du gibt doch später mit return try! JSONDecoder().decode(Self.Type, from: asData) nicht den Type der dekodierten Klasse zurück, sondern eine Instanz der Klasse. Wenn ich mich nicht täusche, musst du lediglich Self.Type durch Self ersetzen (als Rückgabeparameter im Protokoll und dementsprechend in der Default-Implementierung.

    Falls das der Compiler nicht mag (der ist bei Typ-Spielereien mit Protokollen manchmal etwas eigen), würde ich es über ein associatedType ObjectType = Self im Protokoll versuchen, aber ich glaube es sollte so auch schon funktionieren.

    Kleine Zusatz-Anmerkung:
    • Im Protokoll hast du Funktionsargumente als in der Default Implementation
    • Vorsicht mit return try! JSONDecoder().decode(Self.Type, from: asData) - Nutze lieber try? anstatt try!, wenn deine Rückgabetyp eh schon ein Optional ist. Sonst bekommst du einen Runtime Error falls das Decoding mal fehlschlägt.
  • Wolf schrieb:

    Heruhaundo schrieb:

    Da diese auch eine Password Policy enthält, wollte ich sie verschlüsseln.
    Man speichert keine Passworte! Nur den Hash.
    Ich Speicher ja nicht das Passwort sondern eine Password Policy (Gültigkeitsdauer, Länger, erlaubte Zeichen, usw,).
    Darüber könnte man aber Rückschlüsse auf das Passwort ziehen, deshalb will ich sie verschlüsselt speichern.
  • Osxer schrieb:

    Jetzt mal abgesehen von den angesprochenen Bedenken von Wolf und Mattes, versuche ich auf deine Urprungsfrage einzugehen.

    Heruhaundo schrieb:

    Die Fehlermeldung lautet: Type 'Self.Type' cannot conform to 'Decodable'
    Habe deinen Code jetzt nicht ausprobiert, aber augenscheinlich ist es genau das, was die Fehlermeldung besagt. Ich glaube deine Protokoll-Deklaration ist falsch:

    Quellcode

    1. public protocol UserDefault: Codable {
    2. ...
    3. static func getUserDefault(_ key: String, default: Bool) -> Self.Type
    4. ...
    5. }
    Warum ist der Rückgabe-Typ hier denn Self.Type? Du gibt doch später mit return try! JSONDecoder().decode(Self.Type, from: asData) nicht den Type der dekodierten Klasse zurück, sondern eine Instanz der Klasse. Wenn ich mich nicht täusche, musst du lediglich Self.Type durch Self ersetzen (als Rückgabeparameter im Protokoll und dementsprechend in der Default-Implementierung.

    Falls das der Compiler nicht mag (der ist bei Typ-Spielereien mit Protokollen manchmal etwas eigen), würde ich es über ein associatedType ObjectType = Self im Protokoll versuchen, aber ich glaube es sollte so auch schon funktionieren.

    Kleine Zusatz-Anmerkung:
    • Im Protokoll hast du Funktionsargumente als in der Default Implementation
    • Vorsicht mit return try! JSONDecoder().decode(Self.Type, from: asData) - Nutze lieber try? anstatt try!, wenn deine Rückgabetyp eh schon ein Optional ist. Sonst bekommst du einen Runtime Error falls das Decoding mal fehlschlägt.

    Ich probiere es heute Abend gleich aus, mit static func getUserDefault() -> Self? und return try? JSONDecoder().decode(Self.self, from: asData) bekomme ich aber zumindest keinen Compilerfehler mehr.
  • Also ich hab's getestet. So funktioniert es:

    Quellcode

    1. static func getUserDefault(_ defaultConfiguration: Bool = false) -> Self {
    2. if defaultConfiguration {
    3. return Self.defaultConfiguration
    4. } else if let asSealedBox = UserDefaults.standard.object(forKey: Self.userDefaultsKey) as? ChaChaPoly.SealedBox,
    5. let asString = Crypto.encrypt(asSealedBox),
    6. let asData = asString.data(using: .utf8),
    7. let asObject = try? JSONDecoder().decode(Self.self, from: asData) {
    8. return asObject
    9. } else {
    10. return Self.defaultConfiguration
    11. }
    12. }
    Alles anzeigen
    @Osxer: Danke!