{Type 'Self' does not conform to protocol 'Decodable'} or {'DefaultsKeyedArchiverBridge' requires that 'Self' conform to 'Decodable'}

38 views Asked by At

Title: Swift Error: Type 'Self' does not conform to protocol 'Decodable' in SwiftyUserDefaults extension

Body: Hello Swift community,

I'm encountering an issue while working on my Swift project that involves using the SwiftyUserDefaults library. I'm relatively new to Swift development and would appreciate some guidance on resolving this error.

Context: I'm building an iOS app using Swift and incorporating SwiftyUserDefaults to manage user defaults. I've followed the documentation and integrated SwiftyUserDefaults into my project, but I'm encountering an error related to protocol conformance.

Problem: When attempting to use SwiftyUserDefaults to define default values for certain types (such as Date, String, Int, etc.), I'm getting the following error messages:

"Type 'Self' does not conform to protocol 'Decodable'" "'DefaultsKeyedArchiverBridge' requires that 'Self' conform to 'Decodable'" What I've Tried: I've reviewed the Swift documentation on protocols and Codable, but I'm still struggling to understand how to resolve this issue. I've also searched online for similar problems but haven't found a solution that applies to my specific scenario.

Code Snippets: Here's an excerpt from my SwiftyUserDefaults extension where the error occurs:

import Foundation

extension DefaultsSerializable {
    public static var _defaultsArray: DefaultsArrayBridge<[T]> { return DefaultsArrayBridge() }
}
extension Date: DefaultsSerializable {
    public static var _defaults: DefaultsObjectBridge<Date> { return DefaultsObjectBridge() }
}
extension String: DefaultsSerializable {
    public static var _defaults: DefaultsStringBridge { return DefaultsStringBridge() }
}
extension Int: DefaultsSerializable {
    public static var _defaults: DefaultsIntBridge { return DefaultsIntBridge() }
}
extension Double: DefaultsSerializable {
    public static var _defaults: DefaultsDoubleBridge { return DefaultsDoubleBridge() }
}
extension Bool: DefaultsSerializable {
    public static var _defaults: DefaultsBoolBridge { return DefaultsBoolBridge() }
}
extension Data: DefaultsSerializable {
    public static var _defaults: DefaultsDataBridge { return DefaultsDataBridge() }
}

extension URL: DefaultsSerializable {
    #if os(Linux)
    public static var _defaults: DefaultsKeyedArchiverBridge<URL> { return DefaultsKeyedArchiverBridge() }
    #else
    public static var _defaults: DefaultsUrlBridge { return DefaultsUrlBridge() }
    #endif
    public static var _defaultsArray: DefaultsKeyedArchiverBridge<[URL]> { return DefaultsKeyedArchiverBridge() }
}

extension DefaultsSerializable where Self: Codable {
    public static var _defaults: DefaultsCodableBridge<Self> { return DefaultsCodableBridge() }
    public static var _defaultsArray: DefaultsCodableBridge<[Self]> { return DefaultsCodableBridge() }
}

extension DefaultsSerializable where Self: RawRepresentable {
    public static var _defaults: DefaultsRawRepresentableBridge<Self> { return DefaultsRawRepresentableBridge() }
    public static var _defaultsArray: DefaultsRawRepresentableArrayBridge<[Self]> { return DefaultsRawRepresentableArrayBridge() }
}

extension DefaultsSerializable where Self: NSCoding {
    public static var _defaults: DefaultsKeyedArchiverBridge<Self> { return DefaultsKeyedArchiverBridge() }
    public static var _defaultsArray: DefaultsKeyedArchiverBridge<[Self]> { return DefaultsKeyedArchiverBridge() }
}

extension Dictionary: DefaultsSerializable where Key == String {
    public typealias T = [Key: Value]
    public typealias Bridge = DefaultsObjectBridge<T>
    public typealias ArrayBridge = DefaultsArrayBridge<[T]>
    public static var _defaults: Bridge { return Bridge() }
    public static var _defaultsArray: ArrayBridge { return ArrayBridge() }
}
extension Array: DefaultsSerializable where Element: DefaultsSerializable {
    public typealias T = [Element.T]
    public typealias Bridge = Element.ArrayBridge
    public typealias ArrayBridge = DefaultsObjectBridge<[T]>
    public static var _defaults: Bridge {
        return Element._defaultsArray
    }
    public static var _defaultsArray: ArrayBridge {
        fatalError("Multidimensional arrays are not supported yet")
    }
}

extension Optional: DefaultsSerializable where Wrapped: DefaultsSerializable {
    public typealias Bridge = DefaultsOptionalBridge<Wrapped.Bridge>
    public typealias ArrayBridge = DefaultsOptionalBridge<Wrapped.ArrayBridge>

    public static var _defaults: DefaultsOptionalBridge<Wrapped.Bridge> { return DefaultsOptionalBridge(bridge: Wrapped._defaults) }
    public static var _defaultsArray: DefaultsOptionalBridge<Wrapped.ArrayBridge> { return DefaultsOptionalBridge(bridge: Wrapped._defaultsArray) }
}

Question: Could someone please explain why I'm encountering these errors and how I can resolve them? Additionally, I'm open to alternative suggestions for managing user defaults if SwiftyUserDefaults isn't the best solution for my use case.

Tags: swift, ios, swiftyuserdefaults, decodable, protocol-conformance

Thank you in advance for any help or insights you can provide!

1

There are 1 answers

0
Navneet Kaur On

I am giving you a sample class for managing all data type even you can store you data models in it and you don't need to use any other library or class for this.

class Store {
    
    class var authKey: String?
    {
        set{
            Store.saveValue(newValue, .Authorization)
            
        }get{
            return Store.getValue(.Authorization) as? String
        }
    }
    
    class var userDetails: SignUpModel?
    {
        set{
            Store.saveUserDetails(newValue, .userDetails)
        }get{
            return Store.getUserDetails(.userDetails)
        }
    }
    
    static var remove: DefaultKeys!{
        didSet{
            Store.removeKey(remove)
        }
    }
    
    class func resetDefaults() {
        let defaults = UserDefaults.standard
        let dictionary = defaults.dictionaryRepresentation()
        dictionary.keys.forEach { key in
            if key != DefaultKeys.deviceToken.rawValue{
                defaults.removeObject(forKey: key)
            }
        }
    }
    
    //MARK:-  Private Functions
    private class func removeKey(_ key: DefaultKeys)
    {
        UserDefaults.standard.removeObject(forKey: key.rawValue)
        if key == .userDetails{
            UserDefaults.standard.removeObject(forKey: DefaultKeys.Authorization.rawValue)
        }
        UserDefaults.standard.synchronize()
    }
    
    private class func saveValue(_ value: Any? ,_ key:DefaultKeys)
    {
        
        var data: Data?
        if let value = value
        {
            data = try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
        }
        UserDefaults.standard.set(data, forKey: key.rawValue)
        UserDefaults.standard.synchronize()
    }
    
    private class func saveUserDetails<T: Codable>(_ value: T?, _ key: DefaultKeys)
    {
        var data: Data?
        if let value = value
        {
            data = try? PropertyListEncoder().encode(value)
        }
        Store.saveValue(data, key)
    }
    
    private class func getUserDetails<T: Codable>(_ key: DefaultKeys) -> T?{
        if let data = self.getValue(key) as? Data{
            let loginModel = try? PropertyListDecoder().decode(T.self, from: data)
            return loginModel
        }
        return nil
    }
    
    private class func getValue(_ key: DefaultKeys) -> Any
    {
        if let data = UserDefaults.standard.value(forKey: key.rawValue) as? Data{
            if let value = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)
            {
                return value 
            }
            else{
                return ""
            }
        }else{
            return ""
        }
    }
}

If you have any questions feel free to reach or ask any questions.