SwiftUI - 在导航堆栈中弹回不会取消分配视图

Posted

技术标签:

【中文标题】SwiftUI - 在导航堆栈中弹回不会取消分配视图【英文标题】:SwiftUI - Pop back in navigation stack does not deallocate a view 【发布时间】:2020-04-26 21:09:14 【问题描述】:

我想首先突出显示我的视图层次结构。我只有FindUserViewWelcomeView

FindUserView 用于在输入的电子邮件存在时从服务器检索用户。如果是这样,它会自动将我重定向到下一个WelcomeView,我可以在其中输入密码并登录。

我创建了一个repo here 和一个视频SwiftUI - Pop back does not deallocate view

我的FindUserView:---------------------------- 和WelcomeView

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

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

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
            
        
    

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

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

现在我在欢迎视图WelcomeView

但是当我按下这个按钮并弹回来时,我的WelcomeView 仍然存在。

当我使用带有可观察属性状态的@EnvironmentObject 时,我看到它如何反映到已经被忽略的视图中。这是正确的行为吗?还是我需要以某种方式解除WelcomeView?会不会导致内存泄露?

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

【问题讨论】:

【参考方案1】:

实际上并不清楚它是否是缺陷 - SwiftUI 视图是值,因此它们没有 dealloc 东西。看起来NavigationView 只是保留了类似 lastView 的变量,直到它被另一个变量替换。也许值得向 Apple 提交反馈。

同时,这里的解决方案允许推迟真正的目标视图创建,直到完全点击 NavigationLink 并在通过返回按钮从堆栈中删除视图时清理它(使用任何相关资源,如视图模型)。

使用 Xcode 11.4 / ios 13.4 测试

助手代理视图演示者:

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 
    

用法:

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

【讨论】:

好的,谢谢!让我试试你的解决方案,我也向 Apple 提交了一个问题。让我们看看他们会评论什么。 Apple 依靠我的下一个(不确定我是否理解):数据需要控制是否正在进行工作。查看代码,WelcomeView 中的状态似乎是错误的。 showActivityIndi​​cator 在获取开始时设置为 true,但没有设置为 false。该属性不应该是视图的状态,而应该是执行获取的对象的属性。当 fetch 停止时活动指示器将停止,并且视图在空闲时不会消耗任何资源。

以上是关于SwiftUI - 在导航堆栈中弹回不会取消分配视图的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中将绑定传递给导航堆栈中每个视图的最佳方法是啥

SwiftUI @State 变量没有被取消初始化

在 SwiftUI 中放置在导航堆栈中时滚动视图的背景颜色

SwiftUI 垂直 ScrollView 弹回并不显示其中的所有视图

当我在 SwiftUI 中使用 EnvironmentObject 时,选择器正在弹回

如何在颤动中从导航器堆栈中弹出最后三个路由