Vai al contenuto

CONCURRENCY

Cosa imparerò:

  • async-await
  • MainActor
  • DispatchQueue

Il concurrency in Swift si riferisce alla capacità di eseguire più compiti contemporaneamente, migliorando l'efficienza e la reattività delle applicazioni. In Swift, ci sono diverse tecniche per gestire la concurrency, come i thread, le dispatch e i task asincroni, che consentono di eseguire operazioni in background senza bloccare l'interfaccia utente.


// Funzione asincrona per eseguire la chiamata di rete
func fetchData() async throws -> Data {
    // URL della richiesta
    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
    // Esecuzione della richiesta di rete e attesa della risposta
    let (data, _) = try await URLSession.shared.data(from: url)
    // Restituzione dei dati ricevuti
    return data
}

// Esecuzione della funzione asincrona
Task {
    do {
        let data = try await fetchData()
        if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
            print("Risposta del server:", json)
        }
    } catch {
        print("Errore durante la chiamata di rete:", error)
    }
}

Output

Risposta del server: ["title": sunt aut facere repellat provident occaecati excepturi optio reprehenderit, "body": quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto, "id": 1, "userId": 1]

@MainActor è un attributo introdotto in Swift 5.5 per segnalare che una classe o una struttura è isolata al main actor, normalmente usato per aggiornare lo stato collegato alla UI. Questo attributo viene utilizzato principalmente in combinazione con async/await per garantire che le operazioni che modificano lo stato dell'interfaccia utente vengano eseguite in modo sicuro e sincronizzato sul thread principale.

@MainActor
struct MainApp {
    static func main() async {
        // Eseguiamo il nostro codice principale all'interno di una funzione asincrona
        try? await Task.sleep(nanoseconds: 1 * 1_000_000_000) // Simuliamo un'attesa di 1 secondo
        print("Codice principale eseguito sul main actor")
    }
}

In questo esempio, MainApp è un main actor, contrassegnato dall'attributo @MainActor. La funzione main() è una funzione asincrona, che viene eseguita sul main actor. Utilizziamo await per eseguire l'attesa all'interno della funzione asincrona. Essendo contrassegnata come @MainActor, questa funzione può interagire con l'interfaccia utente in modo sincronizzato e sicuro.

Grand Central Dispatch (GCD) è una libreria che permette di gestire l’esecuzione concorrente del codice tramite code. In genere si usa una coda in background per svolgere operazioni pesanti, come il caricamento o l’elaborazione di dati, e poi si torna sulla main queue per aggiornare l’interfaccia utente.

// Simuliamo un'operazione che richiede tempo       
DispatchQueue.global(qos: .userInitiated).async {
    let risultato = "Dati caricati"
    DispatchQueue.main.async {
        print(risultato)
    }
}