在@Observable中使用@AppStorage
所属分类:ios | 发布于 2024-12-26
@Observable是苹果在WWDC23推出的Observation Framework中提出的。可以更加便利的实现类似ObservableOjbect的效果。
但是在@Observable中不支持@AppStorage包装器,我们可以这样使用:
@Observable
class MyModel {
// Externally visible properties
@ObservationIgnored var name: String {
get {
access(keyPath: \.name)
return _name
}
set {
withMutation(keyPath: \.name) {
_name = newValue
}
}
}
// Internal stored properties
@ObservationIgnored @AppStorage("name") private var _name: String = "Bob"
}
比如在自己的项目中使用:
// pipWindowPosition
@ObservationIgnored var pipWindowPosition:PipWindowPosition {
get {
access(keyPath: \.pipWindowPosition)
return _pipWindowPosition
}
set {
withMutation(keyPath: \.pipWindowPosition) {
_pipWindowPosition = newValue
}
}
}
@ObservationIgnored @AppStorage("pipWindowPosition") private var _pipWindowPosition: PipWindowPosition = .topTraining
在stackoverflow中还有人提供了另外一种方法,原理是封装了两个泛型函数来直接操作UserDefaults,没有测试过,这里贴出来:
@Observable class AppPreferences {
// @AppStorage("username") var username: String = ""
public var username: String {
get { appStorageGetter(keyPath: \.username, name: "username", defaultValue: "") }
set { appStorageSetter(keyPath: \.username, name: "username", newValue: newValue) }
}
// Generic functions to help workaround the issue with @AppStorage properties in an @Observable class
private func appStorageGetter<T>(keyPath: KeyPath<AppPreferences, T>, name: String, defaultValue: T) -> T where T : Decodable {
access(keyPath: keyPath)
if let data = UserDefaults.standard.data(forKey: name) {
return try! JSONDecoder().decode(T.self, from: data)
} else {
return defaultValue
}
}
private func appStorageSetter<T>(keyPath: KeyPath<AppPreferences, T>, name: String, newValue: T) where T : Encodable {
withMutation(keyPath: keyPath) {
let data = try? JSONEncoder().encode(newValue)
UserDefaults.standard.set(data, forKey: name)
}
}
}