15

I want to listen to notifications when the app goes to the background and comes back. I'm trying to use the NotificationCenter publishers and have the SwiftUI view listen to them.
I can use a few methods to do it and I'm trying to use two of them but the interesting thing is, that although all seem legit when I put the subscriber in the init() method, it just does not work.
I tried to put it on the main thread but still no success.
Does anyone have any idea why?
Here's my code:

struct ContentView: View {
    @State var isActive = true
    @State var cancellables = Set<AnyCancellable>()
    var body: some View {
        ZStack {
            Image("background")
                .resizable()
                .scaledToFill()
                .edgesIgnoringSafeArea(.all)                        
        }
        .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
            self.isActive = false
        }
        .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification), perform: {_ in
            self.isActive = true
        })
    }

    init() {
        NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)
         //   .receive(on: RunLoop.main)
            .sink(receiveValue: { _ in
                print("init")
            }
            .store(in: &cancellables)
    }
}

Strangely the listener in the onReceive modifier works like a charm. In the init() the print("init") never gets called.

Badro Niaimi
  • 959
  • 1
  • 14
  • 28
hastoro11
  • 203
  • 1
  • 2
  • 5

2 Answers2

17

@State is not ready yet in init, so it cannot be used for such purposes. The approach can be as follows:

var cancellables = Set<AnyCancellable>()
init() {
    NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)
        .sink(receiveValue: { _ in
            print(">> in init")
        })
        .store(in: &cancellables)
}

in such defined cancellables you can store all subscribers created in init, but you will not be able to use it later in code, but this approach is good for once defined notification handlers.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Thanks, that seems to be the problem. I did not want the `@State` wrapper anyway but at a certain point Xcode started complaining that in a struct you can't modify the properties. But now it accepts it. – hastoro11 Jan 02 '20 at 13:16
1

Can you use onAppear?

...
...
  var body: some View {
  ... your body code
  }.onAppear(perform: loadNotification)

  private func loadNotification() {
     NotificationCenter.default.publisher(
     ....
  }

See onAppear:

https://developer.apple.com/documentation/swiftui/view/3278614-onappear

It seems to be the replacement for viewDidLoad

Johnston
  • 20,196
  • 18
  • 72
  • 121