Trying to load an image after the view loads, the model object driving the view (see MovieDetail below) has a urlString. Because a SwiftUI View
element has no life
We can achieve this using view modifier.
ViewModifier
:struct ViewDidLoadModifier: ViewModifier {
@State private var didLoad = false
private let action: (() -> Void)?
init(perform action: (() -> Void)? = nil) {
self.action = action
}
func body(content: Content) -> some View {
content.onAppear {
if didLoad == false {
didLoad = true
action?()
}
}
}
}
View
extension:extension View {
func onLoad(perform action: (() -> Void)? = nil) -> some View {
modifier(ViewDidLoadModifier(perform: action))
}
}
struct SomeView: View {
var body: some View {
VStack {
Text("HELLO!")
}.onLoad {
print("onLoad")
}
}
}
Fully updated for Xcode 11.2, Swift 5.0
I think the viewDidLoad()
just equal to implement in the body closure.
SwiftUI gives us equivalents to UIKit’s viewDidAppear()
and viewDidDisappear()
in the form of onAppear()
and onDisappear()
. You can attach any code to these two events that you want, and SwiftUI will execute them when they occur.
As an example, this creates two views that use onAppear()
and onDisappear()
to print messages, with a navigation link to move between the two:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()) {
Text("Hello World")
}
}
}.onAppear {
print("ContentView appeared!")
}.onDisappear {
print("ContentView disappeared!")
}
}
}
ref: https://www.hackingwithswift.com/quick-start/swiftui/how-to-respond-to-view-lifecycle-events-onappear-and-ondisappear
I hope this is helpful. I found a blogpost that talks about doing stuff onAppear for a navigation view.
Idea would be that you bake your service into a BindableObject and subscribe to those updates in your view.
struct SearchView : View {
@State private var query: String = "Swift"
@EnvironmentObject var repoStore: ReposStore
var body: some View {
NavigationView {
List {
TextField($query, placeholder: Text("type something..."), onCommit: fetch)
ForEach(repoStore.repos) { repo in
RepoRow(repo: repo)
}
}.navigationBarTitle(Text("Search"))
}.onAppear(perform: fetch)
}
private func fetch() {
repoStore.fetch(matching: query)
}
}
import SwiftUI
import Combine
class ReposStore: BindableObject {
var repos: [Repo] = [] {
didSet {
didChange.send(self)
}
}
var didChange = PassthroughSubject<ReposStore, Never>()
let service: GithubService
init(service: GithubService) {
self.service = service
}
func fetch(matching query: String) {
service.search(matching: query) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let repos): self?.repos = repos
case .failure: self?.repos = []
}
}
}
}
}
Credit to: Majid Jabrayilov