.task { } — mi ez, async módosító és adatbetöltés View-ban

Szerző: IT Sectr Megjelenés: 2026-06-26 Olvasási idő: 9 perc

.task { } — egy módosító a SwiftUI-ban, amely az iOS 15-ben került bevezetésre, és elindít egy aszinkron műveletet a View megjelenésekor, valamint automatikusan megszakítja azt a View eltűnésekor. Ellentétben a .onAppear-rel, amely szinkron kódot hajt végre megszakítási lehetőség nélkül, a .task async/await kontextussal működik, és figyelembe veszi a View életciklusát: a View eltűnésekor a SwiftUI meghívja a cancel()-t a létrehozott Task-on. Ez megakadályozza a memóriaszivárgást és a műveletek végrehajtását, miután a View-t már nem kell frissíteni. Az Apple WWDC Session 10132 — Meet async/await in SwiftUI (2024) szerint a .task az előnyben részesített módszer az adatbetöltésre a SwiftUI-ban, mivel biztonságosan együttműködik a Structured Concurrency-vel és automatikusan kezeli az aszinkron művelet élettartamát.

Főbb pontok

  • .task { } — SwiftUI módosító aszinkron adatbetöltéshez a View megjelenésekor, iOS 15-től elérhető.
  • Automatikus megszakítás — a View eltűnésekor a SwiftUI megszakítja a Task-ot, megelőzve a memóriaszivárgást.
  • async/await kontextus — a .task belsejében async hívások érhetők el DispatchQueue vagy Combine nélkül.
  • .task(id:) — azonosítós változat újraindítja a feladatot a megadott érték változásakor.
  • Structured Concurrency — a .task támogatja a Structured Concurrency-t és a TaskGroup-ot párhuzamos műveletekhez.

Mi a .task { } a SwiftUI-ban

.task { } — egy View módosító, amely Task-ot hoz létre async kontextusban, amikor a View megjelenik a képernyőn. A SwiftUI elindítja a megadott closure-t a háttérben, miközben a fő szál szabad marad az UI műveletek számára. Amikor a View eltűnik, a SwiftUI automatikusan megszakítja a Task-ot a Structured Concurrency mechanizmusán keresztül — ez garantálja, hogy az aszinkron művelet nem folytatódik, miután az eredményére már nincs szükség.

Az Apple — Swift Programming Language (2025) szerint a .task a Structured Concurrency koncepciót használja, amely a Swift 5.5-ben került bevezetésre. Minden .task létrehoz egy gyermekfeladatot a szülő View feladatának keretében. Ha a szülő feladat megszakad (a View eltűnik), az összes gyermekfeladat is automatikusan megszakad. Ez radikálisan leegyszerűsíti az aszinkron műveletek életciklusának kezelését a DispatchWorkItem vagy AnyCancellable referenciák manuális tárolásához képest.

Ellentétben a hagyományos @State + manuális hívás .onAppear-ban megközelítéssel, a .task nem igényli a Task referenciájának tárolását későbbi megszakításhoz. A SwiftUI ezt automatikusan teszi, ami csökkenti a boilerplate kód mennyiségét és kiküszöböli a feladat megszakításának elfelejtéséből eredő kockázatot.

swift
struct ArticlesView: View {
    @State var articles: [Article] = []
    @State var error: Error?
    
    var body: some View {
        List(articles) { article in
            Text(article.title)
        }
        .task {
            do {
                articles = await APIClient().fetchArticles()
            } catch {
                self.error = error
            }
        }
    }
}

.task vs .onAppear: főbb különbségek

Sok fejlesztő megszokta, hogy adatokat tölt be a .onAppear-ben, de az async/await és a .task megjelenésével ez a megközelítés elavult. A .onAppear szinkron módon hajtja végre a kódot — az aszinkron műveletekhez a .onAppear-en belül a hívást Task { }-be kell csomagolni, és manuálisan tárolni egy referenciát a lehetséges megszakításhoz. A .task ezt automatikusan teszi.

Jellemző.task { }.onAppear
Async kontextusBeépített async/awaitTask { } csomagolást igényel
Automatikus megszakításIgen, a View eltűnésekorNem, manuálisan kell megvalósítani
Structured ConcurrencyTámogatjaNem támogatja
ÚjraindításCsak az id változásakorMinden megjelenéskor
Apple ajánlásElőnyben részesített módszerSzinkron műveletekhez

A .onAppear továbbra is hasznos szinkron műveletekhez — például naplózáshoz vagy az UI kezdeti konfigurálásához. De aszinkron adatbetöltéshez, hálózati kérésekhez, adatbázis- vagy fájlrendszer-műveletekhez használd a .task-ot. Ez architektúrális szempontból biztonságosabb és tisztább.

swift
// ❌ Régi megközelítés: Task a .onAppear-ben megszakítás nélkül
var loadTask: Task<Void, Never>?
func body() { var body: some View { Text("") }
    .onAppear {
        loadTask = Task { await loadData() }
    }
    .onDisappear { loadTask?.cancel() }

// ✅ Modern megközelítés: .task kezeli a megszakítást
func body() { var body: some View { Text("") }
    .task { await loadData() }

.task(id:) — újraindítás adatváltozáskor

A .task(id:) módosító egy további paramétert — egy azonosítót — fogad. Amikor az azonosító értéke megváltozik, a SwiftUI megszakítja az aktuális feladatot, és újat indít az új azonosítóval. Ez ideális azokhoz a képernyőkhöz, ahol az adatok a kiválasztott paramétertől függenek — például cikklista kategória szerint vagy termékrészletek ID alapján.

swift
struct CategoryView: View {
    let categoryId: Int
    @State var items: [Item] = []
    
    var body: some View {
        List(items) { item in
            Text(item.name)
        }
        .task(id: categoryId) {
            await loadItems(for: categoryId)
        }
    }
    
    func loadItems(for id: Int) async {
        do {
            items = await APIClient().fetchItems(categoryId: id)
        } catch {
            // hiba kezelése
        }
    }
}

Amikor a categoryId megváltozik, a SwiftUI megszakítja az előző kérést, és újat indít. Ez különösen fontos a kategóriák gyors váltogatásakor — a régi kérések nem versenyeznek az újakkal az állapot frissítéséért. .task(id:) nélkül manuálisan kellene követni a változásokat .onChange segítségével, és manuálisan kezelni a Task-ot.

Feladatok megszakítása és isCancelled ellenőrzése

Bár a .task automatikusan megszakítja a feladatot a View eltűnésekor, magának az aszinkron műveletnek együttműködően kell ellenőriznie a megszakítást. A Swift együttműködő megszakítási modellt használ — a Task.cancel() nem állítja le erőszakkal a végrehajtást, csak beállítja az isCancelled flag-et. A feladatban lévő kódnak időszakonként ellenőriznie kell ezt a flag-et.

swift
struct LoadingView: View {
    @State var progress: Double = 0
    
    var body: some View {
        ProgressView(value: progress)
            .task {
                for i in 0..<100 {
                    // Megszakítás ellenőrzése
                    try Task.checkCancellation()
                    
                    await Task.sleep(nanoseconds: 50_000_000)
                    progress = Double(i + 1) / 100.0
                }
            }
    }
}

Task.checkCancellation() CancellationError-t dob, ha a feladat meg lett szakítva. Ez a legegyszerűbb ellenőrzési módszer — bármilyen async kontextusban működik. Alternatíva — a Task.isCancelled manuális ellenőrzése költséges műveletek előtt. Az URLSession hálózati kérések automatikusan megszakadnak a feladat megszakításakor, mivel az URLSession a kezdetektől támogatja a Structured Concurrency-t.

Gyakorlati példák a .task használatára

.task számos forgatókönyvhöz alkalmas: az egyszerű JSON betöltéstől a bonyolult, TaskGroup-pal végzett párhuzamos műveletekig. Nézzünk meg három tipikus használati példát.

Betöltés hibakezeléssel

swift
struct ProfileView: View {
    @State var profile: Profile?
    @State var isLoading = true
    
    var body: some View {
        Group {
            if isLoading {
                ProgressView()
            } else if let profile {
                Text(profile.name)
            } else {
                Text("Betöltés sikertelen")
            }
        }
        .task {
            defer { isLoading = false }
            do {
                profile = await APIClient().fetchProfile()
            } catch {
                // profil nil marad
            }
        }
    }
}

Párhuzamos betöltés TaskGroup-pal

swift
struct DashboardView: View {
    @State var stats: DashboardStats?
    
    var body: some View {
        Text("Irányítópult")
            .task {
                stats = await Task {
                    await withThrowingTaskGroup { group in
                        group.addTask { await API().fetchUsers() }
                        group.addTask { await API().fetchOrders() }
                        group.addTask { await API().fetchRevenue() }
                        
                        return DashboardStats(
                            users: try await group.next(),
                            orders: try await group.next(),
                            revenue: try await group.next()
                        )
                    }
                }.value
            }
    }
}

Gyakori hibák a .task-kal

A leggyakoribb hiba — UI tulajdonságok módosítása a .task-on belül anélkül, hogy átváltanánk a fő szálra. Bár a SwiftUI automatikusan visszaküldi a frissítéseket a fő szálra a @State változásakor async kontextusban, az UIKit elemek közvetlen manipulációja a .task-on belül crash-t okozhat.

  • Elfelejtetted a try/catch-t — a .task nem kezeli automatikusan a hibákat. Minden hibát dobó függvényt do/catch-be kell csomagolni, különben az alkalmazás összeomlik.
  • Race condition — ha több .task(id:) van elindítva különböző id-kkel és ugyanazt az állapotot frissítik, versenyhelyzet alakulhat ki. Használj külön tulajdonságokat különböző adatforrásokhoz.
  • Hosszú szinkron műveletek — a .task nem teszi aszinkronná a szinkron kódot. Ha a .task-on belül nehéz szinkron munka van, csomagold Task.detached-be, vagy helyezd át egy külön async metódusba.
  • CancellationError figyelmen kívül hagyása — a Task.checkCancellation() ellenőrzésekor a CancellationError hibát tovább kell propagálni, nem elnyomni. A megszakítás elnyomása memóriaszivárgáshoz vezethet.
swift
// ❌ Hiba: nincs hibakezelés
.task {
    let data = await fetchData() // hibánál összeomlik!
    items = data
}

// ✅ Helyes: do/catch
.task {
    do {
        items = await fetchData()
    } catch {
        errorMessage = error.localizedDescription
    }
}

Gyakran Ismételt Kérdések

Mi a különbség a .task és a Task { } .onAppear-ben való használata között?

A .task automatikusan megszakítja a feladatot a View eltűnésekor, és támogatja a Structured Concurrency-t. A Task { } a .onAppear-ben megköveteli a feladatra való referenciák manuális tárolását és a cancel() meghívását a .onDisappear-ben. A .task könnyebben olvasható is — egyértelműen jelzi, hogy az adatbetöltés a View életciklusának része.

Használható a .task publisherre való feliratkozásra?

Igen, az AsyncSequence vagy AsyncStream feliratkozáshoz használd a for await value in publisher.values kifejezést a .task-on belül. Ez működik async/await-tel és Combine-nal is a Publisher.values kiterjesztésen keresztül. A View eltűnésekor az iteráció automatikusan véget ér, és a feliratkozás megszakad.

Hogyan működik a .task a TabView-val — újraindul a feladat a lapok váltásakor?

Igen, ha a TabView-n belüli View minden váltáskor újra létrejön. iOS 18-tól kezdve a TabView tárolhatja a View-t a memóriában — ebben az esetben a .task nem indul újra. Használj .task(id:)-t a lap azonosítójával, ha minden váltáskor újra kell tölteni az adatokat.

Mi történik, ha a .task-kal rendelkező View eltűnik a kérés befejezése előtt?

A SwiftUI megszakítja a feladatot a View eltűnésekor. Ha az URLSession kérés a feladaton belül volt, az is megszakad. Ha a feladat nem támogatja az együttműködő megszakítást (pl. nem ellenőrzi az isCancelled-t), a végrehajtás folytatódik, de az eredmény nem kerül alkalmazásra az állapotban, mivel a View már nem létezik.

Használható több .task egyetlen View-n?

Igen, több .task módosító is hozzáadható egy View-hoz. Mindegyik független feladatot hoz létre. Ez kényelmes a különböző adatforrások szétválasztására: az egyik .task a profil betöltésére, a második a WebSocket feliratkozásra, a harmadik a geolokáció figyelésére.

Összefoglalás

  • .task { } — SwiftUI módosító aszinkron műveletekhez automatikus megszakítással a View eltűnésekor.
  • async/await támogatás — a .task belsejében teljes async kontextus érhető el Task csomagolás nélkül.
  • .task(id:) — újraindítja a feladatot az azonosító változásakor, helyettesíti a manuális .onChange-t.
  • Együttműködő megszakítás — használd a Task.checkCancellation()-t a megszakítás ellenőrzésére a feladaton belül.
  • Structured Concurrency — a .task támogatja a TaskGroup-ot és a párhuzamos műveleteket gyermekfeladatok megszakításával.
  • .onAppear helyettesítése — aszinkron adatbetöltéshez használd a .task-ot a .onAppear + Task + .onDisappear kombináció helyett.
  • Hibakezelés — a .task-on belüli összes async hívást do/catch-be kell csomagolni a crash megelőzése érdekében.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is