3

I'm currently developing an application using SwiftUI.

I want to use a method when a view appears.

In the case of the code I attached below, I can use the print method when the app is booted and done some transitions between pages.


But I want to use the print method when I reopen the app like below:

  • 1: run the code on a simulator (I can see the print method works).

  • 2: press a home button.

  • 3: open the app with tap the app icon (I can't see the print method works ).

    (*) I want to use the print method here.

How can I do it as I want in this case?

enter image description here


here is the code:

import SwiftUI

struct ContentView: View {
    
    @State private var selection = 0
 
    var body: some View {
        TabView(selection: $selection){
            Text("First View")
                .onAppear(){
                    print("First")
            }
                .tabItem {
                        Text("First")
                }
                .tag(0)
            
            Text("Second View")
                .tabItem {
                        Text("Second")
                }
                .tag(1)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

ADD:

I found a way to use some function when the app becomes a foreground from a background using sceneWillEnterForeground or sceneWillResignActive in SceneDelegate.swift

But in this case, when the app becomes a foreground with the SecondView also works function. And I want to modify the code to work the function only when the app becomes foreground with the FirstView.

Is there any way to do that?

SceneDelegate.swift

func sceneDidBecomeActive(_ scene: UIScene) {
        print("BecomeActive")
    }
func sceneWillEnterForeground(_ scene: UIScene) {
        print("Foreground")
    }

Xcode: Version 11.7

Swift: Swift 5

pawello2222
  • 46,897
  • 22
  • 145
  • 209
Tio
  • 944
  • 3
  • 15
  • 35
  • 2
    The fact that application goes into background (when you tap Home button) does not mean that view disappeared - it is still there (the same as cmd-tab on macOS) - it is changed application state. So you need to handle different events with same handler. And app active/inactive/background is handled in SceneDelegate (in your case). – Asperi Sep 05 '20 at 14:04
  • @Asperi , Thank you for your comment, is there any way instead of using `onAppear` method in this case? – Tio Sep 05 '20 at 14:37

1 Answers1

7

You may use an @EnvironmentObject to track the application state (by observing notifications):

class AppState: ObservableObject {
    @Published var isActive = true

    private var observers = [NSObjectProtocol]()

    init() {
        observers.append(
            NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { _ in
                self.isActive = true
            }
        )
        observers.append(
            NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { _ in
                self.isActive = false
            }
        )
    }
    
    deinit {
        observers.forEach(NotificationCenter.default.removeObserver)
    }
}

You need to create this (once only) in the SceneDelegate and pass to the ContentView as an @EnvironmentObject:

let appState = AppState()
let contentView = ContentView().environmentObject(appState)

Now you can use the @EnvironmentObject in any view you want:

struct FirstView: View {
    @EnvironmentObject var appState: AppState

    var body: some View {
        Text("First View, isActive: \(appState.isActive.description)")
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209