ios – Unable to change value of @ObservableObject from appDelegate firebaseNotification function


I have configured firebase Notifications for my app. Inside the app delegate function that receives and shows the notification content when the notification is received, i have a logic of a timer, after the times went off, the value of my observable object haveOnGoingCall is set to false. This is important for checking the value of haveOnGoingCall on another view and decide to render it or not further more.

MainContentView:

import SwiftUI
import Foundation

class ClientCallDefinitionsRepro: ObservableObject{
    @Published var haveOnGoingCall: Bool = false
}

struct MainContentView: View {
    @StateObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()
    @State private var isOnGoingCall: Bool = false

    var body: some View {
            ZStack{
                Button(action: {
                    print(self.newCall.haveOnGoingCall)
                }){Text("click")}
                if newCall.haveOnGoingCall{
                    ClientCallInfoViewRepro()
                       .frame(width: 400)
                       .background(Color.yellow)
                       .padding([.bottom], 450)
                       .transition(.slide) // Optional: Add transition animation
                       .onDisappear {
                           DispatchQueue.main.async {
                                self.newCall.haveOnGoingCall = false
                           }
                       }
                }
            }
    }
    
}

Then here’s the code for the function inside for the firebase notification detect and the timer logic is inside of it:

 @State private var timeRemaining = 100
  let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @ObservedObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // Handle the push notification payload

        var timer: Timer?
        var elapsedTime: TimeInterval = 0.0
        let oneMinute: TimeInterval = 10.0  // One minute in seconds
        
//        print("Before setting haveOnGoingCall to true")
//        print(self.newCall.haveOnGoingCall)
        DispatchQueue.main.async {
            self.newCall.haveOnGoingCall = true
            print(self.newCall.haveOnGoingCall, "see here if the notification changed the value of haveOnGoingCall")
        }
    
        DispatchQueue.main.async {
            NotificationCenter.default.post(name: Notification.Name("DidReceiveRemoteNotification"), object: nil)
        }
        
//        print("After setting haveOnGoingCall to true")
//        print(self.newCall.haveOnGoingCall)
        // Start a timer
        print(self.newCall.haveOnGoingCall, "see here if the notification changed the value of haveOnGoingCall after")

        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            elapsedTime += 1.0
            // Check if one minute has passed
            if elapsedTime < oneMinute && self.newCall.haveOnGoingCall{
                DispatchQueue.main.async {
                    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                    AudioServicesPlayAlertSound(SystemSoundID(1322))
                }
            } else{
                // One minute has passed, invalidate the timer and set the condition
                timer.invalidate()
                DispatchQueue.main.async {
                    self.newCall.haveOnGoingCall = false
                    print(self.newCall.haveOnGoingCall)
                    print("newCall setted to false here")
                }
            }
        }

        print("Received push notification: \(userInfo)")

        DispatchQueue.main.async {
            NotificationCenter.default.post(name: Notification.Name("DidReceiveRemoteNotification"), object: nil)
        }
        // Perform background tasks or update UI based on the received payload
        print(self.newCall.haveOnGoingCall)

        completionHandler(.newData)
    }

@main
struct Coonnecta_ClientApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    @ObservedObject var newCall: ClientCallDefinitionsRepro = ClientCallDefinitionsRepro()

    var body: some Scene {
        WindowGroup {
            NavigationView {
                MainContentView(newCall: newCall)
                               .environmentObject(LoginSettings())
                               .onReceive(NotificationCenter.default.publisher(for: Notification.Name("DidReceiveRemoteNotification"))) { _ in
                                   // Handle the notification, update your @StateObject
                                   self.newCall.haveOnGoingCall = true
                               }
                       }
                       .environmentObject(newCall) // Pass the newCall instance
                   }
        }
    }
}

Issue is, after i receive the notification, i set the value of haveOnGoingCall to true, this works fine, and the ClientCallInfoViewRepro in MainContentView is showed correctly and by using the button in the view, i can see that the value of haveOnGoingCall is set fine. After the time goes off, the value of haveOnGoingCall will still be true, altho i set it to be false in the timer logic, and the view ClientCallInfoViewRepro is not closed.

ClientCallInfoViewRepro code:

//
//  ClientCallInfoViewRepro.swift
//  Coonnecta Client
//
//  Created by Anilton on 19/01/2024.
//

import SwiftUI

struct ClientCallInfoViewRepro: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("Client")
                .frame(maxWidth: .infinity, alignment: .leading)
                .font(.system(size: 25, weight: .bold))
                .foregroundColor(.red)

                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Client").font(.headline).bold()
                            Text("Ana Julia").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Device").font(.headline)
                            Text("DCs-DDS.FDGDF").font(.subheadline)
                        }
                    }

                    // Add a spacer to create space between rows

                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Organization").font(.headline).bold()
                            Text("Lalala").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) { // Set alignment to .trailing
                            Text("Plan Type").font(.headline)
                            Text("Golden").font(.subheadline)
                        }
                        .padding(.leading, -120) // Manually adjust the position to the left
                    }
            
                    HStack {
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Blood type").font(.headline).bold()
                            Text("-O").font(.subheadline)
                        }
                        Spacer()
                        VStack(alignment: .leading, spacing: 3) { // Set alignment to .trailing
                            Text("Allergy").font(.headline)
                            Text("No").font(.subheadline)
                        }
                        .padding(.leading, -120) // Manually adjust the position to the left
                    }
            
                    HStack{
                        VStack(alignment: .leading, spacing: 3) {
                            Text("Contacts").font(.headline).bold()
                            Text("2389548348").font(.subheadline)
                        }
                        Spacer()
                    }
                    
                }
                .padding()
            }
    }

struct ClientCallInfoViewRepro_Previews: PreviewProvider {
    static var previews: some View {
        ClientCallInfoViewRepro()
    }
}

How to fix this issue?
If needed the complete code for the app delegate i will provide, thanks in advance.

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img