real time score update for iOS app
i have a screen where i want to fetch the
approach 1: polling
poll the api at a fixed interval (e.g., every 15 seconds) and update only changed scores/minutes
how it works?
-
fetch the data every 15 seconds
-
compare the new response with current in-memory data
-
only update cells (or views) where
score
,minute
orodds
has changed -
this is simple to implement, works with any api but it's not truly real-time, and inefficient if polling too often
iOS implementation
- use a
Timer
in swift to trigger periodic fetch - use diffing to determine which matches changed (using id and checking if score/minute values differ)
- update only the specific rows in a list or table view
example
define the match model
struct Match: Identifiable, Codable, Equatable {
let id: Int
let homeTeam: String
let awayTeam: String
var homeScore: Int
var awayScore: Int
var minute: Int
}
viewmodel with a polling logic
import Foundation
import Combine
class MatchViewModel: ObservableObject {
@Published var matches: [Match] = []
private var timer: Timer?
private let url = URL(string: "http://localhost:8000/api/v1/football/fixtures?date=2025-06-23&timezone=America/Los_Angeles")!
init() {
fetchMatches()
startPolling()
}
deinit {
timer?.invalidate()
}
private func startPolling() {
timer = Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { [weak self] _ in
self?.fetchMatches()
}
}
private func fetchMatches() {
URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else {
print("Fetch error: \(error?.localizedDescription ?? "Unknown error")")
return
}
do {
let newMatches = try JSONDecoder().decode([Match].self, from: data)
DispatchQueue.main.async {
// Only update scores & minutes
for newMatch in newMatches {
if let index = self.matches.firstIndex(where: { $0.id == newMatch.id }) {
// Update only if score or minute changed
if self.matches[index].homeScore != newMatch.homeScore ||
self.matches[index].awayScore != newMatch.awayScore ||
self.matches[index].minute != newMatch.minute {
self.matches[index].homeScore = newMatch.homeScore
self.matches[index].awayScore = newMatch.awayScore
self.matches[index].minute = newMatch.minute
}
} else {
// New match added
self.matches.append(newMatch)
}
}
}
} catch {
print("Decoding error: \(error)")
}
}.resume()
}
}
import SwiftUI
import SwiftUI
struct MatchListView: View {
@StateObject private var viewModel = MatchViewModel()
var body: some View {
List(viewModel.matches) { match in
VStack(alignment: .leading) {
Text("\(match.homeTeam) vs \(match.awayTeam)")
.font(.headline)
HStack {
Text("Score: \(match.homeScore) - \(match.awayScore)")
Spacer()
Text("Min: \(match.minute)'")
}
.font(.subheadline)
}
}
}
}