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?

iOS implementation

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)
            }
        }
    }
}