Firebase & Offline Sync

Gestione Offline Persistence e Sincronizzazione Real-Time in Cloud Firestore con SwiftUI

Una delle funzionalità più potenti di **Cloud Firestore** su iOS è il supporto nativo all'architettura **Offline-First**. L'SDK gestisce automaticamente un database SQLite locale in cui memorizza la cache dei documenti letti e mette in coda le modifiche effettuate dall'utente in assenza di rete, sincronizzandole col server non appena la connessione si ripristina.

1. Abilitare la Cache Persistente su iOS

Negli SDK recenti la persistenza è attiva di default su iOS, ma è possibile personalizzarne le impostazioni per gestire il limite di memoria su disco:

import FirebaseFirestore

func configureFirestoreSettings() {
    let db = Firestore.firestore()
    let settings = db.settings
    
    // Configura la dimensione della cache su disco (es. 100 MB)
    settings.cacheSettings = PersistentCacheSettings(
        sizeBytes: NSNumber(value: 100 * 1024 * 1024)
    )
    db.settings = settings
}

2. Distinguere Dati Locali da Dati del Server con `snapshot.metadata`

Quando l'utente modifica dei dati offline, la vista SwiftUI si aggiorna istantaneamente grazie alla latency compensation. È possibile verificare la provenienza dei dati mediante l'oggetto SnapshotMetadata:

import SwiftUI
import FirebaseFirestore

class FeedViewModel: ObservableObject {
    @Published var posts: [Post] = []
    @Published var isFromCache: Bool = false
    private var listener: ListenerRegistration?

    func fetchPosts() {
        let db = Firestore.firestore()
        listener = db.collection("posts")
            .order(by: "timestamp", descending: true)
            .addSnapshotListener { [weak self] snapshot, error in
                guard let documents = snapshot?.documents else { return }
                
                // Controlla se lo snapshot proviene dalla cache o dal server
                self?.isFromCache = snapshot?.metadata.isFromCache ?? false
                
                self?.posts = documents.compactMap { doc -> Post? in
                    try? doc.data(as: Post.self)
                }
            }
    }
}

3. Mostrare un Indicatore di Stato Sincronizzazione in SwiftUI

In una vista SwiftUI possiamo notificare con eleganza all'utente se i dati visualizzati provengono dalla cache locale:

struct FeedView: View {
    @StateObject private var viewModel = FeedViewModel()

    var body: some View {
        NavigationView {
            VStack {
                if viewModel.isFromCache {
                    HStack {
                        Image(systemName: "wifi.slash")
                        Text("Modalità offline: visualizzazione da cache locale")
                            .font(.caption)
                    }
                    .padding(8)
                    .background(Color.orange.opacity(0.2))
                    .cornerRadius(8)
                }

                List(viewModel.posts) { post in
                    VStack(alignment: .leading) {
                        Text(post.title).font(.headline)
                        Text(post.content).font(.subheadline)
                    }
                }
            }
            .navigationTitle("Feed Real-Time")
            .onAppear { viewModel.fetchPosts() }
        }
    }
}

Conclusione

Progettare app iOS con supporto offline nativo aumenta drasticamente la customer satisfaction, specialmente in mobilità. Per realizzare app robuste ed offline-first con SwiftUI e Firestore, scrivi a diallooyunus@gmail.com.

Yunus Diallo (DialloDev)

Fondatore di Dywtal Digital a Parma (Italia), sviluppatore iOS con oltre 11 app pubblicate. Specialista in architetture resilienti ed offline-first.