从fullScreenCover返回时如何触发onAppear

How to trigger onAppear when returning from fullScreenCover

提问人:dunoiww 提问时间:9/10/2023 更新时间:9/12/2023 访问量:138

问:

onAppear 不会触发

struct ProfileView: View {
    @StateObject var viewModel = ProfileViewViewModel()
    var body: some View {
        NavigationView {
            VStack {
                if let user = viewModel.user {
                    profile(user: user)
                } else {
                    Text("Loading Profile...")
                }
            }
            .navigationTitle("Profile")
        }
        .onAppear {
            viewModel.fetchUser() //this is the problem
        }
        .fullScreenCover(isPresented: $viewModel.showingPreview) {
            PreviewAvatarView()
        }
    }
}

我意识到当我关闭全屏覆盖时,onAppear 没有触发。

iOS 的Swift iPhone SwiftUI Swift3

评论

0赞 Paulw11 9/10/2023
你为什么需要它?如果更改了用户,则模型应反映此内容 - 将模型对象传递到预览视图PreviewAvatarView
0赞 Benzy Neez 9/10/2023
使用怎么样?onDisappearPreviewAvatarView
0赞 dunoiww 9/10/2023
@Paulw11我将图像保存在 firebase 中,因此我需要它来更新 url 以显示头像。如果没有,我必须在视图之间来回切换以触发 onAppear。
0赞 dunoiww 9/10/2023
@BenzyNeez我使用 viewmodel 来分离逻辑和视图,所以这不是一个好方法。
0赞 Paulw11 9/10/2023
您正在产生不必要的网络运营成本。是的,您正在将头像保存在 firebase 中,但您的模型也可以意识到此更改。您的模型是一个可观察的对象,应将其共享到子视图。它可以使用快照侦听器和类似的方法来发布更改,并且您的视图将自动更新

答:

1赞 lorem ipsum 9/10/2023 #1

您可以使用 .onAppeartask

struct ProfileView: View {
    @StateObject var viewModel = ProfileViewViewModel()
    var body: some View {
        NavigationView {
            VStack {
                if let user = viewModel.user {
                    profile(user: user)
                } else {
                    Text("Loading Profile...")
                }
            }
            .navigationTitle("Profile")
        }
        .task(id: viewModel.showingPreview) {
            guard !viewModel.showingPreview else {return} //Check for false
    
            viewModel.fetchUser() //this is the problem
        }
        .fullScreenCover(isPresented: $viewModel.showingPreview) {
            PreviewAvatarView()
        }
    }
}

task将运行,当 是 .onAppearBoolfalse

评论

0赞 dunoiww 9/10/2023
谢谢!我试过了,它确实做到了
0赞 malhal 9/10/2023
同时删除不必要的状态对象
0赞 lorem ipsum 9/10/2023
@malhal这仍然是我不同意你的观点,但我认为苹果每年都会明确表示,虚拟机是一种选择,这是另一个例子
0赞 malhal 9/10/2023
不幸的是,Core Data 团队从来都不擅长 UI 代码,这是另一个令人沮丧的例子。视图状态不应像这样集中化,因为这意味着视图层次结构失效效率不高。并且@State类目前是内存泄漏,因为 init 不是自动闭合的,它短暂地处于早期测试版并被删除。
0赞 lorem ipsum 9/10/2023
@malhal,如果存在泄漏,您应该报告,但 State 和 Observable 旨在协同工作。现在,可观察对象可以像任何其他结构一样放入环境中。
0赞 ScottM 9/10/2023 #2

不会触发,因为你的基础视图没有出现——覆盖它的视图正在消失,这不是一回事。onAppear

但是,有一个很少使用的可选参数,它可以满足您的需求,例如:fullScreenCoveronDismiss

.fullScreenCover(
  isPresented: $viewModel.showingPreview,
  onDismiss: { viewModel.fetchUser() }
) {
  PreviewAvatarView()
}

Apple 文档

0赞 Kapil Shanbhag 9/12/2023 #3

您可以尝试此解决方案。

struct ProfileView: View {
    @StateObject var viewModel = ProfileViewViewModel()
    var body: some View {
        NavigationView {
            VStack {
                if let user = viewModel.user {
                    profile(user: user)
                } else {
                    Text("Loading Profile...")
                }
            }
            .navigationTitle("Profile")
        }
        .onAppear {
            viewModel.fetchUser() //this is the problem
        }
        .fullScreenCover(isPresented: $viewModel.showingPreview) {
            PreviewAvatarView()
        }
        .onChange(of: viewModel.showingPreview) { isFullScreenOpen in
            if !isFullScreenOpen {
                viewModel.fetchUser()
            }//Executed only when full screen cover is closed.
        }
    }
}

每当工作表关闭时,都会执行 viewModel.fetchUser()。