Actori și Izolarea Datelor în Swift: actor, nonisolated și @MainActor în Swift (iOS & macOS)

Ghid complet pentru modelul Actor în Swift: garantarea protecției împotriva condițiilor de concurență (data races), serializarea apelurilor asincrone, izolarea de thread prin @MainActor și metode nonisolated.

Sintaxă Swift
actor DataStore { var cache: [String: Data] = [:] } | @MainActor class ViewModel

Înainte de apariția actorilor, sincronizarea stării partajate între multiple fire de execuție necesita primitive manuale predispuse la erori fatale: NSLock, os_unfair_lock sau cozi seriale DispatchQueue. O singură citire sau scriere nesincronizată ducea la corupere de memorie sau crash-uri imprevizibile.

În Swift, Actorii (actor) sunt tipuri de referință (similare claselor) care garantează izolarea completă a stării mutabile: compilatorul interzice accesul sincron direct la proprietățile actorului din afara domeniului său de izolare, forțând serializarea apelurilor prin await.

Definirea unui Actor Sigur pentru Concurență
// Actorul protejează starea internă 'balanta' împotriva oricărui Data Race:
actor ContBancar {
    let numarCont: String       // Proprietate imutabilă (Sendable)
    private var sold: Double = 0.0 // Stare mutabilă izolată

    init(numarCont: String, soldInitial: Double) {
        self.numarCont = numarCont
        self.sold = soldInitial
    }

    // Metodele interne pot citi și scrie 'sold' în mod sincron:
    func depunere(suma: Double) {
        sold += suma
    }

    func retragere(suma: Double) -> Bool {
        guard sold >= suma else { return false }
        sold -= suma
        return true
    }

    // Cuvântul cheie 'nonisolated' permite apelul sincron din exterior pentru date sigure:
    nonisolated var infoPublica: String {
        return "Cont IBAN: \(numarCont)"
    }
}

// Apelul din exterior este întotdeauna asincron:
func efectueazaOperatiune(pe cont: ContBancar) async {
    // Acces sincron la proprietatea nonisolated:
    print(cont.infoPublica)
    
    // Acces asincron protejat la logica internă mutabilă:
    await cont.depunere(suma: 250.0)
    let reusit = await cont.retragere(suma: 100.0)
    print("Retragere finalizată cu succes: \(reusit)")
}

Global Actorul @MainActor

Platformele Apple impun ca toate modificările asupra interfeței grafice să se execute exclusiv pe firul principal de execuție (Main Thread). Adnotarea @MainActor este un actor global care forțează compilatorul să garanteze că metodele, proprietățile sau întregile clase adnotate rulează pe firul de UI:

@MainActor
final class ArticoleViewModel: ObservableObject {
    @Published var articole: [String] = []
    
    func incarcaArticole() async {
        // Operația grea de rețea rulează pe thread pool cooperativ de fundal:
        let date = await descarcaDePeServer()
        
        // Atribuirea are loc automat pe Main Thread, fără DispatchQueue.main.async manual!
        self.articole = date
    }
}