使用 SceneDelegate.toView() 弹出视图

Popping views using SceneDelegate.toView()

我有一个 UI,您可以在其中 navigate/push 查看如下内容: AView -> BView -> CView -> DView

我想弹出几个视图(从 DView 到 BView)而不是在现有堆栈顶部放置一个新视图 (BView),我找到了执行此操作的方法:

(UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.toBView()

我不明白的是,当我尝试从 DView return 到 BView 时,为什么它会调用 CView 的 init()?

这是我在调试控制台中得到的输出:

AView init
BView init
CView init
DView init
contract.
button pressed
BView init
**CView init**

为什么它会调用 CView 的 init() 以及如何避免这种行为?

AView.swift:

import SwiftUI

struct AView: View {
    
    init() {
        print("AView init")
    }
    

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: BView()) {
                    Text("This is View A, now go to View B.")
                }
            }
        }
    }
}

struct BView: View {
    init() {
        print("BView init")
    }
    

    var body: some View {
        NavigationLink(destination: CView()) {
                Text("This is View B, now go to View C.")
        }
    }
}

struct CView: View {
    
    init() {
        print("CView init")
    }
    
    var body: some View {
        NavigationLink(destination: DView()) {
                Text("This is View C, now go to View D.")
        }
    }
}

struct DView: View {
    init() {
        print("DView init")
    }
    
    var body: some View {
        Button(action: {
            print("button pressed")
            (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.toBView()

        },
               label: {
            Text("Back!")
        })

    }
}

SceneDelegate.swift:

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Create the SwiftUI view that provides the window contents.
        let aView =     AView()
        
        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: AView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
    
    func toBView() {
        let bView = BView()
        window?.rootViewController = UIHostingController(rootView: bView)
    }

}

这种行为并没有错。如果您启动您的应用程序并显示 AView,您将在控制台中看到它从 A 和 B 打印 init。

这是因为 BView() 已经在您的 AView 中初始化,即使您还没有激活 NavigationLink。

NavigationLink(destination: BView()) {

因此,此行为并非特定于您的弹回操作,它在一开始就已经发生了。如果您担心多次调用 init() ,请参阅 Asperi 关于多个 init() 的解决方案