为啥这个 SwiftUI 视图会初始化两次?

Posted

技术标签:

【中文标题】为啥这个 SwiftUI 视图会初始化两次?【英文标题】:Why does this SwiftUI view init twice?为什么这个 SwiftUI 视图会初始化两次? 【发布时间】:2020-04-30 16:55:25 【问题描述】:

为什么在标签栏点击“TV”时,TvAiringTodayView 会初始化 2 次?有时它只加载一次,但大多数情况下每次都发生。当我运行应用程序并单击“电视”标签栏按钮时,我得到以下输出:

initMainView
initMovieMainView
initTvMainView
initTvButtonBarView
initTvAiringTodayView
initTvAiringTodayView

您可能需要尝试两次才能看到它发生。点击时 TvAiringTodayView 似乎不应该初始化两次,但确实如此。

import SwiftUI

struct ContentView: View 

    var body: some View 
        TabView 
            //Movies View
            MovieMainView()
                .tabItem 
                    Image(systemName: "film")
                    Text("Movies")
            

            //TV View
            TvMainView()
                .tabItem 
                    Image(systemName: "tv")
                    Text("TV")
                        
        
    

    init() 
        print("initMainView")
    


struct MovieMainView: View 

    var body: some View 
        VStack 
            Text("MovieMainView")
        
    

    init() 
        print("initMovieMainView")
    


struct TvMainView: View 

    var body: some View 
        VStack 
            ScrollView(.vertical, showsIndicators: false) 
                TvButtonBarView()
            
        
    

    init() 
        print("initTvMainView")
    


struct TvButtonBarView: View 
    @State private var selectedViewType = 0
    var viewType = ["On The Air", "Top Rated", "Popular"]

    var body: some View 
        VStack 
            Picker(selection: $selectedViewType, label: Text("Strength")) 
                ForEach(0 ..< viewType.count ) 
                    Text(self.viewType[$0])
                
            .pickerStyle(SegmentedPickerStyle())

            if selectedViewType == 0 
                TvAiringTodayView()
            
            //            if selectedViewType == 1 
            //                TvTopRatedView()
            //            
            //            if selectedViewType == 2 
            //                TvPopularView()
            //            
        
    

    init() 
        print("initTvButtonBarView")
    


struct TvAiringTodayView: View 

    var body: some View 
        Text("TvAiringTodayView")
    

    init() 
        print("initTvAiringTodayView")
    

【问题讨论】:

除非你需要在init() 中做一些有意义的事情,否则我会使用.onAppear ,因为它只会在视图加载时执行调用。 TabView 是问题所在。鉴于SwiftUI 是新的,它可能需要一些改进。我观察到它会重新加载嵌套在多个Vstacks 中的视图。看看这个answer 寻找可能的解决方案。 【参考方案1】:

我已经测试了这段代码超过 20 次,没有提到任何案例。我相信您面临的问题是某种错误。

与类不同,结构很容易创建和销毁。因此,每次父状态更改时都会调用 TvAiringTodayView 的 init。当selectedViewType != 0 时,结构从内存中清除而被销毁,当selectedViewType == 0 时,结构再次初始化。当stength 选择器更改selectedViewType 的状态时,这会创建多个初始化调用。

【讨论】:

谢谢。感谢您的回答。

以上是关于为啥这个 SwiftUI 视图会初始化两次?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI MVVM:父视图更新时重新初始化子视图模型

如何在 SwiftUI 中再次初始化 View?

SwiftUI 上的 NavigationLink 两次推送视图

深度解析:为何在 SwiftUI 视图的 init 初始化器里无法更改 @State 的值?

深度解析:为何在 SwiftUI 视图的 init 初始化器里无法更改 @State 的值?

为啥自定义 SwiftUI 视图不响应状态变化