Ghid de Migrare la Swift 6: Activarea Modului Strict Concurrency, Rezolvarea Avertismentelor Sendable și Actori în Swift (iOS & macOS)

Ghid complet de migrare la Swift 6: configurarea compilatorului pentru verificarea strictă a concurenței, adaptarea bibliotecilor terțe cu @preconcurrency, corectarea avertismentelor Sendable și izolarea pe @MainActor.

Sintaxă Swift
SWIFT_STRICT_CONCURRENCY = complete | @preconcurrency import LegacyLib

Swift 6 marchează cea mai mare evoluție arhitecturală din istoria limbajului prin activarea Data-Race Safety la compilare. Dacă în Swift 5 codul concurent neglijent putea rula producând coruperi silențioase de memorie în producție, modul de limbaj Swift 6 transformă toate avertismentele de concurență în erori fatale de compilare.

Migrarea unui proiect existent nu trebuie făcută brusc; Apple recomandă o strategie în 3 etape progresive folosind setarea de build Strict Concurrency Checking.

Configurarea Treptată în Xcode Build Settings și Package.swift
// 1. În Package.swift pentru pachete SwiftPM:
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "EnterpriseCore",
    platforms: [.iOS(.v17), .macOS(.v14)],
    targets: [
        .target(
            name: "EnterpriseCore",
            swiftSettings: [
                // Activează noul mod lingvistic Swift 6 complet:
                .swiftLanguageModes([.v6])
            ]
        )
    ]
)

// 2. În Xcode (Build Settings):
// Căutați "Strict Concurrency Checking" și setați:
// - Etapa 1: "Minimal" (verifică doar adnotările explicite)
// - Etapa 2: "Targeted" (verifică codul care a adoptat deja async/await)
// - Etapa 3: "Complete" (simulează comportamentul strict din Swift 6 înainte de switch-ul final)

Cele Trei Tipare Comune de Erori și Rezolvarea Lor

Eroarea 1: Partajarea Instanțelor Mutabile fără Izolare

Mesaj eroare: Capture of 'dateLocale' with non-sendable type 'DateFormatter' in a `@Sendable` closure

// SOLUȚIE: Nu partajați clase mutabile vechi Foundation între thread-uri.
// Creați instanța local în interiorul sarcinii asincrone sau folosiți noul API de formatare din Swift:
Task.detached {
    // În loc de DateFormatter partajat, folosim API-ul modern Value-type Sendable:
    let textFormatat = Date.now.formatted(date: .abbreviated, time: .shortened)
    print("Dată formatată în mod sigur: \(textFormatat)")
}

Eroarea 2: Integrarea cu Biblioteci Terțe Neactualizate (@preconcurrency)

Dacă o dependență externă (cum ar fi un SDK de plăți sau analytics instalat prin CocoaPods / SwiftPM) nu a adăugat încă conformările Sendable, compilatorul Swift 6 va refuza să o compileze. Puteți suprima temporar erorile cu adnotarea @preconcurrency:

// Suprimă avertismentele de concurență generate de tipurile exportate de biblioteca externă:
@preconcurrency import OldAnalyticsSDK

func trackEvent(user: UserProfile) async {
    let tracker = LegacyAnalyticsTracker()
    tracker.logEvent("user_login", properties: user.dictionaryPayload)
}

Eroarea 3: Lipsa Izolării pe Firul Principal a ViewModel-urilor

În SwiftUI, modificarea stării afișate pe ecran trebuie să aibă loc exclusiv pe @MainActor. Adăugați adnotarea la nivel de clasă:

@MainActor
@Observable
final class DashboardViewModel {
    var statistici: [MetricModel] = []
    
    func reincarca() async {
        // Apelul asincron de rețea cedează thread-ul:
        let rezultate = try? await NetworkClient.shared.fetchMetrics()
        // Când se reia execuția, compilatorul garantează prezența pe Main Thread:
        if let rezultate {
            self.statistici = rezultate
        }
    }
}