考虑我们有一个RootView
和一个DetailView
。 DetailView
有它自己的BindableObject,我们称它为DetailViewModel
,并且有以下情况:
RootView
可以通过某种全局事件进行更新,例如错过了
互联网连接或通过自己的数据/视图模型RootView
处理事件时
内容已更新,这导致DetailView
的新结构
被创建DetailViewModel
是DetailView
在初始化时创建的,
将会有DetailViewModel
的另一个引用,并且它的状态(例如所选对象)将丢失如何避免这种情况?
对不起,我没有提供任何代码。这个问题是关于Swift UI的架构概念的,我们试图将声明性结构和引用对象与数据结合起来。
就目前而言,我没有找到一种方法来保留仅与适当视图相对应的引用,也不能将其始终保持在当前状态下的内存/环境中。
让我们添加一些代码来查看如果虚拟机是通过其视图创建的,会发生什么情况
import SwiftUI
import Combine
let trigger = Timer.publish(every: 2.0, on: .main, in: .default)
struct ContentView: View {
@State var state: Date = Date()
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: ContentDetailView(), label: {
Text("Navigation push")
.padding()
.background(Color.orange)
})
Text("\(state)")
.padding()
.background(Color.green)
ContentDetailView()
}
}
.onAppear {
_ = trigger.connect()
}
.onReceive(trigger) { (date) in
self.state = date
}
}
}
struct ContentDetailView: View {
@ObservedObject var viewModel = ContentDetailViewModel()
@State var once = false
var body: some View {
let vmdesc = "View model uuid:\n\(viewModel.uuid)"
print("State of once: \(once)")
print(vmdesc)
return Text(vmdesc)
.multilineTextAlignment(.center)
.padding()
.background(Color.blue)
.onAppear {
self.once = true
}
}
}
class ContentDetailViewModel: ObservableObject, Identifiable {
let uuid = UUID()
}
似乎如果我们将ObservableObject作为@State存储在视图中(而不是作为ObservedObject),则视图将在VM上保持引用
@State var viewModel = ContentDetailViewModel()
有负面影响吗?我们可以这样使用吗?
看来,如果ViewModel保留在View的@State中:
subs
将被重置,但属性将相同Mehhh ...
这种方法还允许您在绑定闭包中保留强引用
import Foundation
import Combine
import SwiftUI
/**
static func instanceInView() -> UIViewController {
let vm = ContentViewModel()
let vc = UIHostingController(rootView: ContentView(viewModel: vm))
vm.bind(uiViewController: vc)
return vc
}
*/
public protocol ViewModelProtocol: class {
static func instanceInView() -> UIViewController
var bindings: Set<AnyCancellable> { get set }
func onAppear()
func onDisappear()
}
extension ViewModelProtocol {
func bind(uiViewController: UIViewController) {
uiViewController.publisher(for: \.parent)
.sink(receiveValue: { [weak self] (parent) in
if parent == nil {
self?.bindings.cancel()
}
})
.store(in: &bindings)
}
}
struct ModelView<ViewModel: ViewModelProtocol>: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<ModelView>) -> UIViewController {
return ViewModel.instanceInView()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<ModelView>) {
//
}
}
struct RootView: View {
var body: some View {
ModelView<ParkingViewModel>()
.edgesIgnoringSafeArea(.vertical)
}
}
答案 0 :(得分:0)
Apple表示,对于存在于SwiftUI之外的数据,我们应该使用ObservableObject。这意味着您必须自己管理数据源。
似乎单个状态容器最适合SwiftUI架构。
typealias Reducer<State, Action> = (inout State, Action) -> Void
final class Store<State, Action>: ObservableObject {
@Published private(set) var state: State
private let reducer: Reducer<State, Action>
init(initialState: State, reducer: @escaping Reducer<State, Action>) {
self.state = initialState
self.reducer = reducer
}
func send(_ action: Action) {
reducer(&state, action)
}
}
您可以将商店的实例传递到SwiftUI应用程序的环境中,它将在所有视图中可用,并且将存储您的应用程序状态而不会造成数据丢失。
我写了一篇有关此方法的博客文章,请查看它以获取更多信息 https://swiftwithmajid.com/2019/09/18/redux-like-state-container-in-swiftui/