How to change thread or reference of NotificationCenter's handler when observing value change

Hello Everyone,

I'm now facing a issue that number counting won't work correctly when I use Notification Center(I tried to narrow down the problem area as below's code and Notification Center seems to be problem's root)

I suspect that the problem cause from Thread location or reference on NotificationCenter's handler when observing value change. So, I think that If I can change thread location or reference following thread location or reference of the method that defined addObserver.

Am I correct? and does someone know how to make the code correct?

Code is below

ContentView.swift


struct ContentView: View {
  @ObservedObject var cht = CompletionHandlerTest()
     
  var body: some View {
    Button(action:{
      cht.startCount(list: ["A", "B","C", "D", "E"]){ isCompleteCount in
        print("countEnd")
      }
    }){
      Text("start")
    }
    .padding()
  }
}

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

CompletionHandlerTest.swift

import SwiftUI

public class CompletionHandlerTest: ObservableObject {
 
  @Published var counter: Int = 0
   
  private let nbc = NotificationBasedCompletion.shared
   
  func startCount(list: [String], completion: @escaping(Bool) -> Void) {
    print("count start")
     
    countTest(items: list, count: 0){ isSuccessful in
      completion(true)
      print("countTest is finished")
    }
  }
 
  private func countTest(items: [String], count: Int, completion: @escaping(Bool) -> Void){
     
    if(count >= items.count){
      completion(true)
    }
    else {
      print("count in countTest -> \(count)")
      nbc.notifyForTest(label: items[count]){ isPrintSuccessful in
         
        print("countTest will call-> count: \(count) + 1")
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
          self.countTest(items: items, count: count+1) { isCountSuccessful in
            completion(true)
          }
        }
      }
    }
  }
   
}

 

NotificationBasedCompletion.swift


final public class NotificationBasedCompletion: NSObject{
   
  public static let shared = NotificationBasedCompletion()
  private var observer: NSObjectProtocol?
     
  func notifyForTest(label: String, completion: @escaping (Bool) -> Void ){
         
    if(observer == nil){
      observer = NotificationCenter.default.addObserver(forName: NSNotification.Name("notifyStatus"), object: nil, queue: .main){ (_) in
         
        let notifyStatus = UserDefaults.standard.value(forKey: "notifyStatus") as? Bool ?? false
         
        if notifyStatus {
          completion(true)
        }
         
      }
    }
     
    //if below code is used, count won't proceed
    generateNotification()
     
    // if below code is used, count will count correctly
    //completion(true)
  }
   
  private func generateNotification() {
    print("let's notify!")
    UserDefaults.standard.set(true, forKey: "notifyStatus")
    NotificationCenter.default.post(name:NSNotification.Name("notifyStatus"), object: nil)
  }

   
}

When executing above code, then print as below

count start
count in countTest -> 0
let's notify!
countTest will call-> count: 0 + 1
count in countTest -> 1
let's notify!
countTest will call-> count: 0 + 1
count in countTest -> 1
let's notify!
countTest will call-> count: 0 + 1
count in countTest -> 1

I hope that someone knows about the issue. Best regards,

Not sure if this would help, a simpler solution would be to use a timer

struct ContentView: View {
    
    @StateObject var model = Model()
    
    var body: some View {
        VStack {
            Button(!model.isStarted ? "Start" : "Stop") {
                model.toggle()
            }
            Text(String(model.counter))
        }
    }
}

class Model: ObservableObject {
    
    @Published var counter = 0
    @Published var isStarted = false
    
    private var timer: Timer?
    
    func toggle() {
        if isStarted {
            stop()
        } else {
            start()
        }
    }
    
    private func start() {
        timer = makeTimer()
        isStarted = true
    }
    
    private func stop() {
        timer?.invalidate()
        isStarted = false
    }
    
    private func makeTimer() -> Timer {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
            self?.counter += 1
        }
    }
}
How to change thread or reference of NotificationCenter's handler when observing value change
 
 
Q