UserDefaults - по умолчанию...?


Я сделал это универсальный класс, который помогает мне считывания значений по умолчанию пользователя. Кроме того, злоупотребляя несколько UserDefaults... Что ты видишь? Я могу сделать несколько экземпляров поделиться ссылкой?

class DefaultValue<V> {
    var userDefaults = UserDefaults()
    let name : String
    let defValue : V

    init(name: String, defValue: V) {
        self.name = name
        self.defValue = defValue
    }

    func get() -> V {
        if userDefaults.object(forKey: name) == nil {
            return defValue
        }
        switch defValue {
        case is Int:
            return userDefaults.integer(forKey: name) as! V
        case is Bool:
            return userDefaults.bool(forKey: name) as! V
        case is String:
            return userDefaults.string(forKey: name) as! V
        default:
            return defValue
        }
    }

    func set(value: V) {
        userDefaults.set(value, forKey: name)
    }

    func reset() {
        userDefaults.set(defValue, forKey: name)
    }
}

Использование:

class MyDefaults {
    let LOGGED_IN = DefaultValue<Bool> (name: "logged_in", defValue: false)
    let USERNAME = DefaultValue<String> (name: "username", defValue: "")
}

var settings = MyDefaults()
if settings.LOGGED_IN.get() {
    settings.LOGGED_IN.set(value: true)
} else {
    settings.LOGGED_IN.reset()
}


258
1
задан 4 марта 2018 в 04:03 Источник Поделиться
Комментарии
2 ответа

Принудительное приведения as! V в get() способ может показаться безопасными на первый
взгляд, поскольку вы делаете некоторый тип проверки перед. Но они не являются:
Если значение по умолчанию для некоторых ключ существует, но имеет неправильный тип, то
ваша программа может рухнуть. Это может, например, произойти, если вы измените
типа некоторое значение по умолчанию между релизов программы. Вы можете легко
воспроизвести проблему, установив значение по умолчанию несовместимые
типа, прежде чем получить его с вашего класса:

UserDefaults.standard.set([1, 2, 3], forKey: "username")

class MyDefaults {
let USERNAME = DefaultValue<String> (name: "username", defValue: "Joe")
}

print(MyDefaults.USERNAME.get())

какие сбои в

return userDefaults.string(forKey: name) as! V
// Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Этого можно избежать с дополнительным кастинг as? Vи тогда
весь get() способ упрощается

func get() -> V {
return userDefaults.object(forKey: name) as? V ?? defValue
}

В качестве бонуса, код теперь работает не только с целыми числами, логическими значениями и
строк, но с всех типов (при условии, что они являются “UserDefaults совместимо”).


Я не вижу смысла создавать отдельные UserDefaultsэкземпляров,
вы можете поделиться стандартного экземпляра:

let userDefaults = UserDefaults.standard


В reset() способ может просто удалить значение вместо того, чтобы
значение по умолчанию:

func reset() {
userDefaults.removeObject(forKey: name)
}

Возможным преимуществом является то, что вы можете загрузить его с другой
значение по умолчанию позже.


Я хотел бы использовать “по умолчанию” как ярлык аргумент в метод init:

init(name: String, default defValue: V) {
self.name = name
self.defValue = defValue
}

Это выглядит приятнее, когда называют

let USERNAME = DefaultValue<String> (name: "username", default: "")

а также имитирует subscript(_:default:) Свифт словари.

В set() метод должен иметь пустой спор этикетки

func set(_ value: V) {
userDefaults.set(value, forKey: name)
}

как, например, set(_:forKey:).


Если вашим намерением class MyDefaults чтобы избежать глобальных переменных
и чтобы обеспечить “пространство имен”: это также может быть достигнуто с
случае-меньше enum:

enum MyDefaults {
static let USERNAME = DefaultValue<String>(name: "username", default: "")
}

MyDefaults.USERNAME.set("elcuco")
print(MyDefaults.USERNAME.get())

так что факты должны быть созданы.


Именование: по системе Swift API и принципы проектирования:


Имена типов и протоколов UpperCamelCase. Все остальное lowerCamelCase

так и должно быть

enum MyDefaults {
static let loggedIn = DefaultValue<Bool> (name: "logged_in", default: false)
static let userName = DefaultValue<String>(name: "username", default: "")
}

вместо LOGGED_IN и USERNAME.

1
ответ дан 6 марта 2018 в 09:03 Источник Поделиться

Позволяет добавить новый конструктор:

init(name: String, default defValue: V, userDefaults: UserDefaults) {
self.name = name
self.defValue = defValue
self.userDefaults = userDefaults
}

Мне не нравится идея введения параметров по умолчанию программисты, использующие эту библиотеку. Новое использование должно выглядеть так:

enum Settings {
static let userDefaults = UserDefaults()
static let loggedIn = DefaultValue<Bool> (name: "logged_in", default: false, userDefaults: userDefaults)
static let userName = DefaultValue<String> (name: "username", default: "", userDefaults: userDefaults)
}

0
ответ дан 12 марта 2018 в 10:03 Источник Поделиться