1 year ago

#355085

test-img

tHatpart

Working with Timers in SwiftUI table view

I am trying to have a live count down timer in my SwiftUI TableView, but it's currently not updating. I have done this in UIKit and trying a similar approach with SwiftUI's lifecycle, but currently not working. The implementation is showing a snapshot of the countdown for some cells, but not all, and it isn't a live countdown, meaning it'll show 17 minutes and 12 seconds, but it isn't changing to 11 seconds then 10 etc. But I can see from the print statement in the timer service class that the timeString is updating. Not sure why this isn't working.

struct ListTakeCell: View {
    
    @ObservedObject var presenter: TakeCellViewModel
    
    var body: some View {
        contentView
            .foregroundColor(.white)
            .cornerRadius(16)
            .onAppear {
                presenter.timerService.startTimer()
            }
            .onDisappear {
                presenter.timerService.stopTimer()
            }
            
    }

var timerView: some View {
        Text(presenter.timerService.timerString)
            .padding(8)
            .background(Color(UIColor.lightGray))
            .foregroundColor(presenter.timerService.timerString == "Expired" ? .red : Color(UIColor.darkGray))
            .cornerRadius(15)
    }

}

In the view's viewModel I have the TimerService class like so: @ObservedObject var timerService: TimerService

class TimerService: ObservableObject {
    
    @Published var timerString = "loading"
    private var timer = Timer()
    private var targetDate: Date!
    
    lazy var durationFormatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.day, .hour, .minute, .second]
        formatter.unitsStyle = .abbreviated
        
        return formatter
    }()
    
    init(expiresOn: Date) {
        self.targetDate = expiresOn
        startTimer()
    }
    
    deinit {
        timer.invalidate()
    }
    
    func startTimer() {
        self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerTicked(_:)), userInfo: nil, repeats: true)
    }
    
    func stopTimer() {
        timer.invalidate()
    }
    
    @objc private func timerTicked(_ timer: Timer){
        if targetDate.isEarlier(than: Date()){
            timerString = "Expired"
            return
        }
        
        guard let timeString = durationFormatter.string(from: targetDate.timeIntervalSince(Date())) else {return}
        print("TIMER TICKED: \(timeString)")
        self.timerString = timeString
    }
}



class TakeCellViewModel: ObservableObject {
    @Published var take: TakeOBJ!
    @Published var authorName: NSAttributedString = NSAttributedString(string: "")
    @Published var authorProfileImage: UIImage = UIImage.defaultAvatar
    @ObservedObject var timerService: TimerService
    
    
    init(take: TakeOBJ) {
        self.take = take
        timerService = TimerService(expiresOn: take.expiresOn.iso8601withFractionalSeconds ?? Date())
        loadAuthor()
    }
}

ios

swift

swiftui

observedobject

0 Answers

Your Answer

Accepted video resources