在支持 iOS 13.0 的同时在 iOS 14.0 中使用 @StateObject
Posted
技术标签:
【中文标题】在支持 iOS 13.0 的同时在 iOS 14.0 中使用 @StateObject【英文标题】:Using @StateObject in iOS 14.0 while supporting iOS 13.0 【发布时间】:2020-11-28 00:11:03 【问题描述】:我需要帮助找到在 ios 14.0 中支持新 @StateObject 并在 iOS 13.0 中仍然支持某些替代方案的最佳方式。诚然,我不知道 iOS 13.0 中最好的方法是什么。以下是我目前拥有的。
有人对更好的方法有想法吗?
struct HomeView: View
let viewModel: HomeViewModel
var body: some View
if #available(iOS 14, *)
HomeViewWrapper(viewModel: viewModel)
else
CompatibleHomeViewWrapper(viewModel: viewModel)
@available(iOS 14, *)
private struct HomeViewWrapper: View
@StateObject var viewModel: HomeViewModel
var body: some View
CompatibleHomeView(viewModel: viewModel)
private struct CompatibleHomeViewWrapper: View
@State var viewModel: HomeViewModel
var body: some View
CompatibleHomeView(viewModel: viewModel)
struct CompatibleHomeView: View
@ObservedObject var viewModel: HomeViewModel
var body: some View
Text(viewModel.someRandomName)
【问题讨论】:
使用@ObservedObject
非常相似,iOS 13支持
实际上在这种情况下,我根本看不到 HomeViewWrapper 的必要性。在内部创建对象时需要 StateObject 包装器,但您拥有外部所有权,即使在父视图之外,所以不需要状态对象,因为在视图重建时不会重新创建 HomeViewModel。
@loremipsum。是的,@ObservedObject
是类似的,但它在 Apple 的文档和 WWDC 视频中都是我们不应该使用的。 @ObservedObject
仅适用于我们确实拥有资源的所有权。
@Asperi。虽然 HomeView 不会创建 HomeViewModel,但它确实拥有对它的所有权。 HomeViewModel 被创建并传递给 HomeView,然后 HomeView 将拥有它。
【参考方案1】:
您可以通过将自定义 propertyWrapper 包裹在 @State 和 @ObservedObject 周围来获得 @StateObject 行为,如下所示:
import Combine
import PublishedObject // https://github.com/Amzd/PublishedObject
/// A property wrapper type that instantiates an observable object.
@propertyWrapper
public struct StateObject<ObjectType: ObservableObject>
where ObjectType.ObjectWillChangePublisher == ObservableObjectPublisher
/// Wrapper that helps with initialising without actually having an ObservableObject yet
private class ObservedObjectWrapper: ObservableObject
@PublishedObject var wrappedObject: ObjectType? = nil
init()
private var thunk: () -> ObjectType
@ObservedObject private var observedObject = ObservedObjectWrapper()
@State private var state = ObservedObjectWrapper()
public var wrappedValue: ObjectType
if state.wrappedObject == nil
// There is no State yet so we need to initialise the object
state.wrappedObject = thunk()
if observedObject.wrappedObject == nil
// Retrieve the object from State and observe it in ObservedObject
observedObject.wrappedObject = state.wrappedObject
return state.wrappedObject!
public init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType)
self.thunk = thunk
我自己也使用这个,所以我会保持更新: https://gist.github.com/Amzd/8f0d4d94fcbb6c9548e7cf0c1493eaff
注意:最受好评的评论是 ObservedObject 非常相似,这根本不是真的。
StateObject
在视图初始化之间保留对象并通过 willChangeObserver 将对象更改传递给视图。
这个解释非常粗略,有更好的地方请阅读它,因为它是 SwiftUI 的一个有影响力的部分。
【讨论】:
以上是关于在支持 iOS 13.0 的同时在 iOS 14.0 中使用 @StateObject的主要内容,如果未能解决你的问题,请参考以下文章