我创建了这个泛型类,它帮助我从用户默认值中读取值。除了滥用几个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()
}发布于 2018-03-06 21:47:25
强制转换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.standardreset()方法可以简单地删除该值,而不是设置默认值:
func reset() {
userDefaults.removeObject(forKey: name)
}一个可能的优点是以后可以使用不同的默认值检索它。
我将在init方法中使用“default”作为参数标签:
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设计指南:
类型和协议的名称为
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。
发布于 2018-03-12 10:20:37
让我们添加一个新的构造函数:
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)
}https://codereview.stackexchange.com/questions/188799
复制相似问题