为 Swiftui 视图转换 @State 的计算属性
Posted
技术标签:
【中文标题】为 Swiftui 视图转换 @State 的计算属性【英文标题】:Convert computed property for @State for Swiftui Views 【发布时间】:2021-05-11 17:40:48 【问题描述】:我是 SwiftUI 的新手,我想基本上转换我的计算属性,以便在 SwiftUI 视图中使用 combine 等。我不能那样使用它,因为“设置”不适用于我的 SwiftUI 视图,而且我在这里有点挣扎。 也许有人有一个很好的解决方案,我如何将它与 combine 转换为在 swift ui 中使用。
存储服务将 Authdata 保存到 userdefaults 中。
var currentAuthData: AuthData?
get
return self.storageService.get(AuthData.self, forKey: authDataStorageKey)
set
if let value = newValue
self.storageService.store(value, forKey: authDataStorageKey)
【问题讨论】:
"get set
不适用于我的 SwiftUI 视图" -- 怎么回事?从语法上讲,这里看起来不一定有什么问题。您能否为minimal reproducible example 提供足够的代码并解释您看到的结果与您的预期有何不同?
很难在没有更多信息的情况下提供帮助。一个常见的错误是将状态放在视图中。在 SwiftUI 中,视图是结构,每帧重新实例化一次(每秒 100 次)。确保将状态保存在 ObservableObject 中并将其传递给视图:developer.apple.com/documentation/swiftui/…。
【参考方案1】:
这就是在 SwiftUI 中转换计算属性的方法,方法是将其设为 @propertyWrapper。如果您需要,我添加了一个使用组合读取数据的解决方案。我还让你的属性是可选的。
我认为这是您要保存的模型。struct AuthData
var name: String
var email: String
为您的属性包装器准备协议,以便能够使用 Optional 将其设置为 nil。
public protocol AnyOptional
var isNil: Bool get
extension Optional: AnyOptional
public var isNil: Bool self == nil
扩展 UserDefaults 以符合此协议并且是可选的。
extension UserDefault where Value: ExpressibleByNilLiteral
init(key: String, _ container: UserDefaults = .standard)
self.init(key: key, defaultValue: nil, container: container)
创建与 SwiftUI 视图的 getter 和 setter 相同的属性包装器。这是一个通用的,可以用于任何类型。您可以在此代码块之后的 UserDefaults 扩展中设置它们。
import Combine
@propertyWrapper
struct UserDefault<Value>
let key: String
let defaultValue: Value
var container: UserDefaults = .standard
// Set a Combine publisher for your new value to
// always read its changes when using Combine.
private let publisher = PassthroughSubject<Value, Never>()
var wrappedValue: Value
get
// Get the new value or nil if any.
container.object(forKey: key) as? Value ?? defaultValue
set
// Check if the value is nil and remove it from your object.
if let optional = newValue as? AnyOptional, optional.isNil
container.removeObject(forKey: key)
else
// Set your new value inside UserDefaults.
container.set(newValue, forKey: key)
// Add the newValue to your combine publisher
publisher.send(newValue)
var projectedValue: AnyPublisher<Value, Never>
publisher.eraseToAnyPublisher()
在 UserDefaults 中创建扩展以在代码中使用您的属性包装器。
extension UserDefaults
@UserDefault(key: "authDataStorageKey", defaultValue: nil)
static var savedAuthData: AuthData?
// You can create as many @propertyWrapper as you want that fits your need
使用示例
// Set a new value
UserDefaults.savedAuthData = AuthData(name: "Muli", email: "muli@***.com")
// Read the saved value
print(UserDefaults.savedAuthData as Any)
// When using combine
var subscriptions = Set<AnyCancellable>()
UserDefaults.$savedAuthData
.sink savedValue in
print(savedValue as Any) // Yours saved value that changes over time.
.store(in: &subscriptions)
【讨论】:
以上是关于为 Swiftui 视图转换 @State 的计算属性的主要内容,如果未能解决你的问题,请参考以下文章
如何将我的 SwiftUI 视图的 @State 交换为我的视图模型 @Published 变量?
一旦新的 SwiftUI 视图完全加载,@State 变量就会被清除
如何根据 SwiftUI 中的 @State 更改导航视图的导航视图样式?