首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UserDefaults -缺省值.?

UserDefaults -缺省值.?
EN

Code Review用户
提问于 2018-03-04 16:51:48
回答 2查看 524关注 0票数 1

我创建了这个泛型类,它帮助我从用户默认值中读取值。除了滥用几个UserDefaults..。你看到什么?我可以让一些实例共享一个引用吗?

代码语言:javascript
复制
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)
    }
}

用法:

代码语言:javascript
复制
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()
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2018-03-06 21:47:25

强制转换as! Vget()方法中乍一看可能是安全的,因为您以前做过一些类型检查。但事实并非如此:如果某个键的默认值存在,但类型不对,那么您的程序就会崩溃。例如,如果在程序发布之间更改某些默认值的类型,就会发生这种情况。在使用类检索默认值之前,可以通过将默认值设置为不兼容类型,轻松地再现问题:

代码语言:javascript
复制
UserDefaults.standard.set([1, 2, 3], forKey: "username")

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

print(MyDefaults.USERNAME.get())

它会在

代码语言:javascript
复制
return userDefaults.string(forKey: name) as! V
// Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

使用可选的强制转换as? V可以避免这一点,然后整个get()方法简化为

代码语言:javascript
复制
func get() -> V {
    return userDefaults.object(forKey: name) as? V ?? defValue
}

值得注意的是,该代码现在不仅适用于整数、布尔和字符串,而且适用于所有类型(前提是它们“与UserDefaults兼容”)。

我认为没有理由创建单独的UserDefaults实例,您可以共享标准实例:

代码语言:javascript
复制
let userDefaults = UserDefaults.standard

reset()方法可以简单地删除该值,而不是设置默认值:

代码语言:javascript
复制
func reset() {
    userDefaults.removeObject(forKey: name)
}

一个可能的优点是以后可以使用不同的默认值检索它。

我将在init方法中使用“default”作为参数标签:

代码语言:javascript
复制
init(name: String, default defValue: V) {
    self.name = name
    self.defValue = defValue
}

打电话的时候看起来更好看

代码语言:javascript
复制
let USERNAME = DefaultValue<String> (name: "username", default: "")

还模仿了斯威夫特词典的subscript(_:default:)

set()方法应该有一个空的参数标签

代码语言:javascript
复制
func set(_ value: V) {
    userDefaults.set(value, forKey: name)
}

比如,set(_:forKey:)

如果class MyDefaults的目的是避免全局变量,并提供一个“命名空间”:这也可以通过没有情况的enum来实现:

代码语言:javascript
复制
enum MyDefaults {
    static let USERNAME = DefaultValue<String>(name: "username", default: "")
}

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

这样就不必创建任何实例。

命名:根据Swift设计指南

类型和协议的名称为UpperCamelCase。其他一切都是lowerCamelCase

所以应该是

代码语言:javascript
复制
enum MyDefaults {
    static let loggedIn = DefaultValue<Bool> (name: "logged_in", default: false)
    static let userName = DefaultValue<String>(name: "username", default: "")
}

而不是LOGGED_INUSERNAME

票数 1
EN

Code Review用户

发布于 2018-03-12 10:20:37

让我们添加一个新的构造函数:

代码语言:javascript
复制
init(name: String, default defValue: V, userDefaults: UserDefaults) {
    self.name = name
    self.defValue = defValue
    self.userDefaults = userDefaults
}

我不喜欢将默认设置强加给使用此库的程序员。新用法应该如下所示:

代码语言:javascript
复制
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
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/188799

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档