持久化属性包装器 是一个 Swift 库,旨在使在 Apple 平台上的 UserDefaults
数据库中持久化变量变得极其容易。
要使用 持久化属性包装器,你只需将一个变量注解为 @Persisted
。它支持标准的 UserDefaults
类型(Int
、String
、Bool
、Date
等),以及 RawRepresentable
枚举(其中 RawValue
可在 UserDefaults
中存储),以及任何符合 Codable
或 NSSecureCoding
的类型。当然,也支持这些类型的任何 Optional
包装器。类型有效性在编译时进行检查:尝试在任何非支持类型的变量上使用将导致编译时错误。
在你的变量上添加 @Persisted
属性。
初始化的第一个参数是字符串键,值将以此键存储在 UserDefaults
中。如果类型是非 Optional 的,你还必须提供一个 defaultValue
,当 UserDefaults
中没有存储值时,将使用该默认值。
例如
@Persisted("UserSetting1", defaultValue: 42)
var someUserSetting: Int
@Persisted("UserSetting2") // defaultValue not necessary since Int? is an Optional type
var someOtherUserSetting: Int?
想要存储枚举值?如果枚举具有受支持在 UserDefaults
中存储的 backing type,那么这些枚举也可以标记为 @Persisted
,并且存储在 UserDefaults
中的实际值将是枚举的原始值 (raw value)。例如
enum AppTheme: Int {
case brightRed
case vibrantOrange
case plainBlue
}
struct ThemeSettings {
// Stores the underlying integer backing the selected AppTheme
@Persisted("theme", defaultValue: .plainBlue)
var selectedTheme: AppTheme
}
任何 codable 类型也可以被持久化;这会将变量的 JSON 编码表示形式存储在 UserDefaults 中。例如
struct AppSettings: Codable {
var welcomeMessage = "Hello world!"
var isSpecialModeEnabled = false
var launchCount = 0
@Persisted(encodedDataKey: "appSettings", defaultValue: .init())
static var current: AppSettings
}
// Example usage: this will update the value of the stored AppSettings
func appDidLaunch() {
AppSettings.current.launchCount += 1
}
请注意,必须使用参数标签 encodedDataKey
。这是为了消除关于使用哪种存储方法的歧义,因为 UserDefaults
可存储的类型也可能是 Codable
的。
例如,以下两个变量通过不同的机制存储
// Stores the integer in UserDefaults
@Persisted("storedAsInteger", defaultValue: 10)
var storedAsInteger: Int
// Store the data of a JSON-encoded representation of the value. Don't use on iOS 12!
@Persisted(encodedDataKey: "storedAsData", defaultValue: 10)
var storedAsData: Int
注意: 在 iOS 12 上,使用 encodedDataKey
初始化器处理将编码为 JSON 片段 的值(例如 Int
、String
、Bool
等)将导致崩溃。这是由于在 iOS 13 之前发布的 Swift 运行时中的一个 错误。在这些情况下,使用 encodedDataKey
没有任何好处。
任何符合 NSSecureCoding
的 NSObject
也可以被持久化;这会将从 NSKeyedArchiver
获取的对象编码表示形式存储在 UserDefaults 中。例如
class CloudKitSyncManager {
@Persisted(archivedDataKey: "ckServerChangeToken")
var changeToken: CKServerChangeToken?
}
请注意,必须使用参数标签 archivedDataKey
。如上所述,这是为了消除关于使用哪种存储方法的歧义。
注意: 此存储机制仅在 iOS 11 及更高版本上受支持。
默认情况下,@Persisted
属性存储在 UserDefaults.standard
数据库中;要将值存储在不同的位置,请将 storage:
参数传递给属性包装器
extension UserDefaults {
static var alternative = UserDefaults(suiteName: "alternative")!
}
@Persisted("alternativeStoredValue", storage: .alternative)
var alternativeStoredValue: Int?
毕竟,网络上有很多类似实用程序的示例。例如,John Sundell 的这篇文章 展示了如何用几行代码编写一个 @UserDefaultsBacked
属性包装器。
然而,在开发 我的应用程序 期间,我发现我真的想在 UserDefaults
中存储枚举值。对于任何由整数或字符串支持的枚举,都有一个明显的理想实现 - 存储枚举的原始值。为了提供一个统一的 API 来持久化 UserDefaults
支持的类型以及由 UserDefaults
支持的类型支持的枚举值,这证明有点棘手;加上需要一切也在任何支持类型的 Optional
包装器上工作,问题变得更加复杂。一旦为我的应用程序解决了,我就想为什么不打包起来呢?
在 Xcode 中添加 https://github.com/AndrewBennet/PersistedPropertyWrapper.git
作为 Swift Package Dependency。
要通过 CocoaPods 安装,请将以下行添加到你的 Podfile
pod 'PersistedPropertyWrapper', '~> 2.0'
将 Sources
目录的内容复制到你的项目中。