🐼 SwiftUI 使用包装器属性封装 UserDefaults
2023/12/24背景:开发 app 合理规划 UserDefault 的 KeyValue 很重要,如果前期没有合理规划进行统一管理,后期维护非常麻烦。
本文使用 SwiftUI 包装器属性 propertyWrapper
来封装 UserDefaults,所有的缓存在 Defaults 定义,使用时可以定义 @Default(.key) var key
拿到相关值。
//
// UserDefaultsManager.swift
// BarrageWords
//
// Created by csd on 2023/9/14.
//
import Foundation
import SwiftUI
// MARK: 管理应用所有的 UserDefaults
public class Defaults: ObservableObject {
public static let shared = Defaults()
@AppStorage("hasPro") var hasPro: Bool = false // 是否订阅 pro
}
// MARK: UserDefaults 添加 @Default 包装器
// - 使用方法: @Default(\.key) var key
@propertyWrapper
public struct Default<T>: DynamicProperty {
@ObservedObject
private var defaults: Defaults
private let keyPath: ReferenceWritableKeyPath<Defaults, T>
public init(_ keyPath: ReferenceWritableKeyPath<Defaults, T>, defaults: Defaults = .shared) {
self.keyPath = keyPath
self.defaults = defaults
}
public var wrappedValue: T {
get { defaults[keyPath: keyPath] }
nonmutating set { defaults[keyPath: keyPath] = newValue }
}
public var projectedValue: Binding<T> {
Binding(
get: { defaults[keyPath: keyPath] },
set: { value in
defaults[keyPath: keyPath] = value
}
)
}
}
// UserDefaults 支持 Date 类型
extension Date: RawRepresentable{
public typealias RawValue = String
public init?(rawValue: RawValue) {
guard let data = rawValue.data(using: .utf8),
let date = try? JSONDecoder().decode(Date.self, from: data) else {
return nil
}
self = date
}
public var rawValue: RawValue{
guard let data = try? JSONEncoder().encode(self),
let result = String(data:data,encoding: .utf8) else {
return ""
}
return result
}
}
使用方式:
import SwiftUI
struct ContentView: View {
@Default(\.hasPro)
private(set) var hasPro: Bool
var body: some View {
Text(hasPro ? "已订阅": "还没呢。")
}
}