Skip to content

VAndrJ/VADefaultsMacro

Repository files navigation

VADefaults

StandWithUkraine Support Ukraine

Language SPM Platform

VADefaults introduces macro to simplify UserDefaults usage and errors prevention.

@UserDefaultsValue

Adds a getter and setter wrapping UserDefaults.

Example 1:

@UserDefaultsValue(defaultValue: "Empty")
var value: String

// expands to 

var value: String {
    get {
        UserDefaults.standard.string(forKey: "value") ?? "Empty"
    }
    set {
        UserDefaults.standard.setValue(newValue, forKey: "value")
    }
}

Example 2:

@UserDefaultsValue(key: "customKey", defaults: .testDefaults)
var value: Int

// expands to 

var value: Int {
    get {
        UserDefaults.testDefaults.integer(forKey: "customKey")
    }
    set {
        UserDefaults.testDefaults.setValue(newValue, forKey: "customKey")
    }
}

@CodableUserDefaultsValue

Adds a getter and setter wrapping UserDefaults for Codable values.

Example 1:

@CodableUserDefaultsValue
var myCodableValue: MyCodable?

// expands to 

var myCodableValue: MyCodable? {
    get {
        UserDefaults.standard.data(forKey: "myCodableValue").flatMap {
            try? JSONDecoder().decode(MyCodable.self, from: $0)
        }
    }
    set {
        UserDefaults.standard.set(try? JSONEncoder().encode(newValue), forKey: "myCodableValue")
    }
}

Example 2:

@CodableUserDefaultsValue(encoder: customEncoder, decoder: customDecoder)
var myCodableValue: MyCodable?

// expands to 

var myCodableValue: MyCodable? {
    get {
        UserDefaults.standard.data(forKey: "myCodableValue").flatMap {
            try? customDecoder.decode(MyCodable.self, from: $0)
        }
    }
    set {
        UserDefaults.standard.set(try? customEncoder.encode(newValue), forKey: "myCodableValue")
    }
}

@RawUserDefaultsValue

Adds a getter and setter wrapping UserDefaults for RawRepresentable values.

Example 1:

@RawUserDefaultsValue(rawType: Int.self)
var value: MyRawRepresentable?

// expands to 

var value: MyRawRepresentable? {
    get {
        (UserDefaults.standard.object(forKey: "value") as? Int).flatMap(MyRawRepresentable.init(rawValue:))
    }
    set {
        UserDefaults.standard.setValue(newValue?.rawValue, forKey: "value")
    }
}

Example 2:

@RawUserDefaultsValue(rawType: Int.self, defaultValue: MyRawRepresentable.undefined)
var value: MyRawRepresentable

// expands to 

var value: MyRawRepresentable {
    get {
        (UserDefaults.standard.object(forKey: "value") as? Int).flatMap(MyRawRepresentable.init(rawValue:)) ?? MyRawRepresentable.undefined
    }
    set {
        UserDefaults.standard.setValue(newValue.rawValue, forKey: "value")
    }
}

@UserDefaultsData

Adds a variable and initializer to the class, and adds getters and setters to the variables wrapping UserDefaults. Dependent macroses:

  • @DefaultsValue
  • @RawDefaultsValue
  • @CodableDefaultsValue

Example 1:

@UserDefaultsData
class Defaults {
    var someVariable: Int
    let someConstant = true
}

// expands to 

class Defaults {
    var someVariable: Int {
        get {
            userDefaults.integer(forKey: "someVariable")
        }
        set {
            userDefaults.setValue(newValue, forKey: "someVariable")
        }
    }
    let someConstant = true

    private let userDefaults: UserDefaults

    init(userDefaults: UserDefaults = UserDefaults.standard) {
        self.userDefaults = userDefaults
    }
}

Example 2:

@UserDefaultsData(defaults: .test)
public class Defaults {
    @DefaultsValue(key: "customKey")
    var someVariable: Int
    var computedVariable: Bool { true }
}

// expands to 

public class Defaults {
    var someVariable: Int {
        get {
            userDefaults.integer(forKey: "customKey")
        }
        set {
            userDefaults.setValue(newValue, forKey: "customKey")
        }
    }
    var computedVariable: Bool { true }

    private let userDefaults: UserDefaults

    public init(userDefaults: UserDefaults = UserDefaults.test) {
        self.userDefaults = userDefaults
    }
}

Example 3:

@UserDefaultsData
public class Defaults {
    @DefaultsValue
    static var someVariable: Int // <-- error, not allowed
    @DefaultsValue
    class var someVariable: Int // <-- error, not allowed
}

TBD:

  • Value and defaultValue types comparison improvements.

  • UserDefaultsData additions.

  • Codable check. Throwable.

  • RawRepresentable improvements.

Author

Volodymyr Andriienko, vandrjios@gmail.com

License

VADefaults is available under the MIT license. See the LICENSE file for more info.