I’m currently building out a project where a user could create multiple timers however I’m running into the following error. "Instance method ‘onReceive(_:perform:)’ requires that ‘CountdownTimer’ conform to ‘Publisher’". I just can’t figure out how to get Countdown Timer to conform to Publisher.
Here is the code for my timer object:
struct CountdownTimer: Identifiable {
let id = UUID()
let name: String
var minutes: Int
var seconds: Int
var countdown: Int {
let totalTime = seconds + (minutes * 60)
return totalTime
}
}
func timeString(time: Int) -> String {
return String(format: "%01i:%02i", minutes, seconds)
}
class CountdownTimers: ObservableObject {
@Published var timers = [CountdownTimer]()
}
My Content View:
struct ContentView: View {
@Environment(\.presentationMode) var presentationMode
@ObservedObject var countdownTimers = CountdownTimers()
@State private var showingAddSheet = false
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
GeometryReader { geometry in
ZStack {
Color.pastelGreen
.edgesIgnoringSafeArea(.all)
VStack {
ScrollView {
ForEach(countdownTimers.timers) { timer in
ZStack {
CardView()
.overlay(
HStack {
VStack(alignment: .leading) {
Text("\(timer.countdown)")
.font(.custom("Quicksand-Bold", size: 30))
Text(" \(timer.timeString(time: timer.countdown))")
.font(.custom("Quicksand-Bold", size: 40))
.onReceive(timer){ _ in
if timers.countdown > 0 {
timers.countdown -= 1
}
}
The error is happening on the .OnReceive(timer) line. the minutes and seconds are created on a different "AddView" but I don’t believe that the issue is related to that section.
Any help would be greatly appreciated.
>Solution :
You’re shadowing the name timer. It appears first here:
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
Then, later, you use it again here:
ForEach(countdownTimers.timers) { timer in
Swift is going to assume you always mean the timer in the most-recently-defined scope, so when you use .onReceive, it assumes you mean timer from the ForEach (which is of type CountdownTimer) and not the Timer defined earlier.
To fix this, use a different name in your ForEach and adjust your code (such as the Text elements) to use the new name.