SwiftUI-在导航堆栈中弹出不会取消分配视图 [英] SwiftUI - Pop back in navigation stack does not deallocate a view

查看:85
本文介绍了SwiftUI-在导航堆栈中弹出不会取消分配视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先要突出显示我的视图层次结构.我只有 FindUserView WelcomeView .

如果输入的电子邮件存在,则

FindUserView 用于从服务器检索用户.如果是这样,那么它将自动将我重定向到下一个 WelcomeView ,我可以在其中输入密码并登录.

我已经创建了 -----------------

通过按 FindUserView 上的NEXT按钮,我从数据库中获取用户:

  func fetchUser(带有电子邮件:String){userService.getUser(with:email){(结果)在切换结果{案例.success(_):self.showActivityIndi​​cator = falseself.showingAlert =假self.showWelcomeView = true休息案例.失败:self.showingAlert = true休息}}} 

我使用 NavigationView 并通过更改上面的 showWelcomeView 状态以编程方式显示 WelcomeView :

  NavigationLink(目标:WelcomeView(),isActive:$ showWelcomeView){EmptyView()} 

现在我在欢迎视图中 WelcomeView .

但是当我按下此按钮并弹出时,我的 WelcomeView 仍然存在.

当我将 @EnvironmentObject 与可观察的属性状态一起使用时,我看到了它如何反映到已经关闭的视图中.这是正确的行为吗?还是我需要以某种方式取消分配 WelcomeView ?会导致内存泄漏吗?

我有点担心,因为在 UIKit 中,当您在导航堆栈中弹出视图控制器时, UINavigationController 会通过自动从数组中删除视图控制器来将其释放.如何在SwiftUI中正确弹出?

解决方案

实际上尚不清楚是否有缺陷-SwiftUI视图是值,因此没有 dealloc 东西.看起来 NavigationView 只是保留了 lastView 变量,直到被另一个变量替代为止.也许值得向苹果提交反馈.

与此同时,这里是一种解决方案,当通过后退"按钮从堆栈中删除视图时,可以推迟真正目标视图的创建,直到准确地点击 NavigationLink 并清理它(带有任何相关资源,例如视图模型).

通过Xcode 11.4/iOS 13.4测试

助手代理视图演示者:

  struct LinkPresenter<内容:视图> ;:视图{让内容:()->内容@State private var invlidated = falseinit(@ViewBuilder _ content:@escaping()-> Content){self.content =内容}var body:some View {团体 {如果是自我{EmptyView()} 别的 {内容()}}.onDisappear {self.invlidated = true}}} 

用法:

  NavigationLink(目标:LinkPresenter {WelcomeView()},isActive:$ showWelcomeView){EmptyView()} 

I would like to start by highlighting my views hierarchy. I just have FindUserView and WelcomeView.

FindUserView is used for retrieving users from the server if the entered email exists. If so, then it automatically redirects me to the next WelcomeView where I can enter password and login.

I've created a repo here and a video SwiftUI - Pop back does not deallocate view

My FindUserView: ---------------------------- and WelcomeView:

-----------------

By pressing NEXT button on FindUserView I fetch a user from the database:

func fetchUser(with email: String) {
        userService.getUser(with: email) { (result) in
            switch result {
            case .success(_):
                self.showActivityIndicator = false
                self.showingAlert = false
                self.showWelcomeView = true
                break
            case .failure:
                self.showingAlert = true
                break
            }
        }
    }

I use NavigationView and programatically show WelcomeView by changing showWelcomeView state above:

NavigationLink(destination: WelcomeView(), isActive: $showWelcomeView) { EmptyView() }

Now I am on welcome view WelcomeView.

But when I press this button and pop back, my WelcomeView still exists.

As I use @EnvironmentObject with observable property state I see how it reflects to the view which is already dismissed. Is this correct behaviour? Or do I need to dealloc WelcomeView somehow? Does it lead to memory leaks?

I am a bit worry as in UIKit when you pop back in navigation stack the view controller it is deallocated by UINavigationController by removing view controller from the array automatically. How to pop back correctly in SwiftUI?

解决方案

Actually it is not clear if it is defect or not - SwiftUI views are values, so there is no dealloc thing for them. It looks like NavigationView just keeps something like lastView variable until it is replaced with another one. Maybe worth submitting feedback to Apple.

Meanwhile here is solution that allows to defer real destination view creation until exactly NavigationLink tapped and cleanup it (w/ any related resources, like view model) when view is removed from stack by Back button.

Tested with Xcode 11.4 / iOS 13.4

Helper proxy view presenter:

struct LinkPresenter<Content: View>: View {
    let content: () -> Content

    @State private var invlidated = false
    init(@ViewBuilder _ content: @escaping () -> Content) {
        self.content = content
    }
    var body: some View {
        Group {
            if self.invlidated {
                EmptyView()
            } else {
                content()
            }
        }
        .onDisappear { self.invlidated = true }
    }
}

Usage:

NavigationLink(destination: LinkPresenter { WelcomeView() }, 
    isActive: $showWelcomeView) { EmptyView() }

这篇关于SwiftUI-在导航堆栈中弹出不会取消分配视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆