如何为可选类型@AppStorage属性设置非空初始默认值并正常持久化
问题原因
- 原生
@AppStorage仅为非可选类型提供了带默认值的构造器,可选类型的默认构造方法不支持直接传入默认值,因此直接赋值写法无法编译通过。 - 在
init中直接判断赋值时,@AppStorage包装的持久化值还未从UserDefaults完成读取,此时访问属性永远返回nil,所以每次启动都会覆盖已有旧值。
解决方案
方案1:扩展AppStorage实现可选类型带默认值的构造器
仅需扩展一次即可全局使用,写法和原生API完全对齐:
import SwiftUI extension AppStorage where Value == String? { init(wrappedValue: Value, _ key: String, store: UserDefaults? = nil) { let targetStore = store ?? .standard // 仅当持久化中不存在该key时写入默认值 if targetStore.object(forKey: key) == nil { targetStore.set(wrappedValue, forKey: key) } self.init(key, store: targetStore) } }
使用时直接按你最初的写法即可编译通过,且不会覆盖已有持久化值:
@AppStorage("navItemSelected") var navItemSelected: String? = "default"
如果需要支持更多可选类型(比如Int?、Bool?等),可以把扩展改成泛型版本:
extension AppStorage where Value: ExpressibleByNilLiteral { init<T>(wrappedValue: Value, _ key: String, store: UserDefaults? = nil) where Value == T?, T: _DefaultStored { let targetStore = store ?? .standard if targetStore.object(forKey: key) == nil { targetStore.set(wrappedValue, forKey: key) } self.init(key, store: targetStore) } }
方案2:用非可选存储+可选计算属性中转
不需要自定义扩展,完全使用原生API实现,兼容性更好:
// 底层用非可选类型存储,直接设置默认值 @AppStorage("navItemSelected") private var storedNavItemSelected: String = "default" // 对外暴露可选类型,适配NavigationLink入参要求 var navItemSelected: String? { get { storedNavItemSelected } set { storedNavItemSelected = newValue ?? "default" } }
内容的提问来源于stack exchange,提问作者Steve M
相关产品推荐
相关产品推荐

