viewDidLoad in SwiftUI

289 阅读3分钟

在SwiftUI中与UIKit VC中的viewDidLoad方法等价的是什么?

如果你使用UIKit中开发过App,那么你一定会想知道,SwiftUI中与viewDidLoad方法等价的是什么。

坏消息是,SwiftUI没有能直接取代viewDidLoad()的方法。

最接近的方法是OnAppear()onDisAppear(),这两个方法相当于UIKit中的viewDidAppear()viewDidDisAppear()

如果你真的想要viewDidLoad()方法的行为,那么你必须自己实现它。幸运的是,实现流程并不是非常复杂。

SwiftUI中的viewDidLoad

我们可以使用SwiftUI中的onAppear()中的修饰器去模拟viewDidLoad()行为。

要实现viewDidLoad方法,我们需要完成以下两点:

  1. 我们需要知道视图是什么时候加载的。在这个例子中,我们可以使用onAppear()修饰器。它可能无法传递确切的意义,但是我认为这是最接近UIKit中的视图加载。
  2. 我们在这个视图的生命周期中,只能加载一次。既然我们想要知道它是不是第一次出现,那么我们需要在视图中保存一个状态值。@State变量对于内部状态,即只在这个视图中使用,的改变非常完美。

举个例子,我将会在SpyView中尝试去实现viewDidLoad()方法。

import SwiftUI
​
struct SpyView: View {
    
    @State private var viewDidLoad = false
    
    var body: some View {
        Text("Spy")
            .onAppear {
                print("onAppear")
                if viewDidLoad {
                    viewDidLoad = true
                    print("viewDidLoad")
                }
            }
    }
}
  1. 首先我们创建了一个@State变量去记录我们是否已经执行过了onAppear行为。
  2. 我们使用onAppear修饰器去检测视图是否已经显示/加载。
  3. 如果viewDidLoad变量是false,那么就意味着onAppear方法第一次被调用。
  4. 然后我们将viewDidLoad变量置为true,然后执行只属于viewDidLoad的逻辑。

为了测试它,我将SpyView放到navigation视图中。然后进入到详情视图,当返回时,将会触发onAppear行为。

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink("Push to Detail") {
                    Text("Detail")
                        .font(.largeTitle)
                }
                SpyView()
            }
            .font(.largeTitle)
        }
    }
}

当App加载完成的时候,你会看到调试窗口中同时出现"OnAppear"和"viewDidLoad"。

但是当视图消失后,再出现,我们会发现,并不会触发viewDidLoad中的逻辑。

将viewDidLoad写成视图装饰器

每次都实现上面的逻辑看起来非常麻烦。如果你将会多次使用它,那么将它制作成一个视图装饰器会是一个非常好的选择。

我将会创建onViewDidLoad修饰器。

首先我们创建一个新的ViewModifier。我们可以从前面的例子中拷贝大多数的代码。

struct ViewDidLoadModifier: ViewModifier {
    
    @State private var viewDidLoad = false
    
    let action: (() -> Void)?
    
    func body(content: Content) -> some View {
        content
            .onAppear {
                if viewDidLoad == false {
                    viewDidLoad = true
                    action?()
                }
            }
    }
}

然后我们创建一个视图的扩展,来更方便的使用它。我在这里拷贝了onAppear的函数签名:

extension View {
    func viewDidLoad(perform action: (() -> Void)? = nil) -> some View {
        return modifier(ViewDidLoadModifier(action: action))
    }
}

上面就是所有的你需要创建一个可重用的viewDidLoad装饰器的步骤。下面是如何使用它:

var body: some View {
    NavigationView {
        VStack {
            NavigationLink("Push to Detail") {
                Text("Detail")
                    .font(.largeTitle)
            }
            SpyView()
                .onAppear {
                    print("onAppear")
                }
                .viewDidLoad {
                    print("viewDidLoad")
                }
        }
        .font(.largeTitle)
    }
}

Thx for reading.