Search code examples
iosswifttimerpublisher

How to cancel/invalidate timer of type AnyPublisher<Date,Never> in SwiftUI?


I'm new in the Combine world and i have var timer: AnyPublisher<Date,Never> to 're-use' the timer i have in the ContentView for my SecondView, do i have to invalidate/cancel the timer when i no longer need it? If yes, how to do it?

In the previous code with a timer of type Timer.TimerPublisher if i had to cancel it I did it using: timer.upstream.connect().cancel() and now of course it keeps giving me this error: Value of type 'AnyPublisher<Date, Never>' has no member 'upstream'


Solution

  • Maybe something like this can help?

    private var timerSubscription: AnyCancellable?
    
    func setupTimer(every interval: TimeInterval, repeats: Bool, onReceive: @escaping (() -> Void)) {
        invalidateTimer()
    
        timerSubscription = Timer
            .publish(every: interval, on: .main, in: .common)
            .autoconnect()
            .sink { _ in
                onReceive()
                if !repeats {
                    self.invalidateTimer()
                }
            }
    }
    
    func invalidateTimer() {
        timerSubscription?.cancel()
    }
    

    full service:

    final class CombineTimerService {
    
    // MARK: - Public Properties
    
    var isCancelled: Bool {
        return timerSubscription == nil
    }
    
    // MARK: - Private Properties
    
    private var timerSubscription: AnyCancellable?
    private var onReceive: (() -> Void)?
    
    // MARK: - Public
    
    func setupTimer(every interval: TimeInterval, repeats: Bool, onReceive: @escaping (() -> Void)) {
        invalidateTimer()
        self.onReceive = onReceive
    
        timerSubscription = Timer
            .publish(every: interval, on: .main, in: .common)
            .autoconnect()
            .sink { _ in
                onReceive()
                if !repeats {
                    self.invalidateTimer()
                }
            }
    }
    
    func invalidateTimer() {
        timerSubscription?.cancel()
        onReceive = nil
    }
    
    func fire() {
        onReceive?()
    }
    }