Search code examples
swiftuiswiftui-navigationlink

.onAppear is calling when I navigated back to a view by clicking back button


I have two views written in swiftUI , say for example ViewA and ViewB. onAppear() of ViewA has an apiCall which calls when initially the view is loaded. I navigate to ViewB from ViewA using navigation link and on clicking back button in ViewB the onAppear() of ViewA is called.

• Is there any way to stop calling onAppear() while navigated back from a view

• I am looking swiftUI for something like 'ViewDidLoad' in UIKit given a sample of my code

struct ContentView: View {
    var body: some View {
        NavigationView{
            List(viewModel.list){ item in
               NavigationLink(
                destination: Text("Destination"),
                label: {
                    Text(item.name)
                })
            }
            .onAppear{
                viewModel.getListApiCall()
            }
     
        }
    }
}

Solution

  • Overview

    • SwiftUI is quite different from the way UIKit works. It would be best to watch the tutorials (links below) to understand how SwiftUI and Combine works.
    • SwiftUI is a declarative framework so the way we approach is quite different. It would be best not to look for a direct comparison to UIKit for equivalent functions.

    Model:

    • Let the model do all the work of fetching and maintaining the data
    • Ensure that your model conforms to ObservableObject
    • When ever any @Published property changes, it would imply that the model has changed

    View:

    • Just display the contents of the model
    • By using @ObservedObject / @EnvironmentObject SwiftUI would observe the model and ensure that the view states in sync with any changes made to the model
    • Notice that though the model fetches the data after 2 seconds, the view reacts to it and displays the updated data.

    Model Code:

    class Model: ObservableObject {
        
        @Published var list = [Item]()
        
        init() {
            fetchItems()
        }
        
        private func fetchItems() {
            
            //To simulate some Async API call
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
                self?.list = (1...10).map { Item(name: "name \($0)") }
            }
        }
    }
    
    struct Item: Identifiable {
        
        var name: String
        
        var id : String {
            name
        }
    }
    

    View Code:

    import SwiftUI
    
    struct ContentView: View {
        
        @ObservedObject var model: Model
        
        var body: some View {
            NavigationView{
                List(model.list){ item in
                    NavigationLink(destination: Text("Destination")) {
                        Text(item.name)
                    }
                }     
            }
        }
    }
    

    Reference:

    SwiftUI

    Combine