.task { } — nedir, async değiştirici ve View'de veri yükleme

Yazar: IT Sectr Yayınlanma: 2026-06-26 Okuma süresi: 9 dk

.task { }, iOS 15'te tanıtılan ve bir View göründüğünde asenkron bir işlem başlatan ve View kaybolduğunda otomatik olarak iptal eden bir SwiftUI değiştiricisidir. İptal imkanı olmadan senkron kod çalıştıran .onAppear'ın aksine, .task async/await bağlamıyla çalışır ve View yaşam döngüsünü dikkate alır: View kaybolduğunda, SwiftUI oluşturulan Task üzerinde cancel() çağrısı yapar. Bu, bellek sızıntılarını ve View'ın artık güncellenmesi gerekmediği halde işlemlerin yürütülmesini önler. Apple WWDC Session 10132 — Meet async/await in SwiftUI (2024)'e göre, .task SwiftUI'de veri yüklemek için tercih edilen yöntemdir çünkü Structured Concurrency ile güvenli bir şekilde çalışır ve asenkron işlemin ömrünü otomatik olarak yönetir.

Önemli Noktalar

  • .task { } — View göründüğünde asenkron veri yükleme için SwiftUI değiştiricisi, iOS 15'ten itibaren kullanılabilir.
  • Otomatik iptal — View kaybolduğunda SwiftUI Task'ı iptal eder, bellek sızıntılarını önler.
  • async/await bağlamı — .task içinde DispatchQueue veya Combine olmadan async çağrıları kullanılabilir.
  • .task(id:) — belirtilen değer değiştiğinde görevi yeniden başlatan tanımlayıcılı varyant.
  • Structured Concurrency — .task, paralel işlemler için Structured Concurrency ve TaskGroup'u destekler.

SwiftUI'de .task { } Nedir

.task { }, View ekranda göründüğünde async bağlamında bir Task oluşturan bir View değiştiricisidir. SwiftUI sağlanan closure'ı arka plan iş parçacığında çalıştırır ve ana iş parçacığını UI işlemleri için serbest bırakır. View kaybolduğunda, SwiftUI Structured Concurrency mekanizması aracılığıyla Task'ı otomatik olarak iptal eder — bu, asenkron işlemin sonucu artık gerekli olmadıktan sonra da yürütülmeye devam etmemesini garanti eder.

Apple — Swift Programming Language (2025)'e göre, .task Swift 5.5'te tanıtılan Structured Concurrency kavramını kullanır. Her .task, üst View'ın görevi kapsamında bir alt görev oluşturur. Üst görev iptal edilirse (View kaybolursa), tüm alt görevler de otomatik olarak iptal edilir. Bu, DispatchWorkItem veya AnyCancellable referanslarını manuel olarak saklamaya kıyasla asenkron işlemlerin yaşam döngüsü yönetimini kökten basitleştirir.

@State + .onAppear'da manuel çağrı içeren geleneksel yaklaşımın aksine, .task daha sonra iptal için Task'a bir referans saklamayı gerektirmez. SwiftUI bunu otomatik olarak yapar, tekrarlayan kodu azaltır ve bir görevi iptal etmeyi unutma riskini ortadan kaldırır.

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: Temel Farklar

Birçok geliştirici .onAppear içinde veri yüklemeye alışkındır, ancak async/await ve .task'in gelişiyle bu yaklaşım güncelliğini yitirmiştir. .onAppear kodu senkron olarak çalıştırır — .onAppear içindeki asenkron işlemler için, çağrıyı Task { } içine sarmak ve olası iptal için manuel olarak bir referans tutmak gerekir. .task bunu otomatik olarak yapar.

Özellik.task { }.onAppear
Async bağlamıYerleşik async/awaitTask { } sarmalayıcısı gerekli
Otomatik iptalEvet, View kaybolduğundaHayır, manuel olarak uygulanmalı
Structured ConcurrencyDesteklerDesteklemez
Yeniden çalıştırmaSadece id değiştiğindeView her göründüğünde
Apple tavsiyesiTercih edilen yöntemSenkron işlemler için

.onAppear senkron işlemler için hala kullanışlıdır — örneğin, günlükleme veya başlangıç UI kurulumu. Ancak asenkron veri yükleme, ağ istekleri, veritabanı veya dosya sistemi işlemleri için .task kullanın. Mimari açıdan daha güvenli ve temizdir.

swift
// ❌ Eski yaklaşım: .onAppear'da iptalsiz Task
var loadTask: Task<Void, Never>?
func body() { var body: some View { Text("") }
    .onAppear {
        loadTask = Task { await loadData() }
    }
    .onDisappear { loadTask?.cancel() }

// ✅ Modern yaklaşım: .task iptali yönetir
func body() { var body: some View { Text("") }
    .task { await loadData() }

.task(id:) — Veri Değişiminde Yeniden Başlatma

.task(id:) değiştiricisi ek bir parametre — bir tanımlayıcı kabul eder. Tanımlayıcının değeri değiştiğinde, SwiftUI mevcut görevi iptal eder ve yeni tanımlayıcıyla yeni bir görev başlatır. Bu, verilerin seçilen bir parametreye bağlı olduğu ekranlar için idealdir — örneğin, kategoriye göre makale listesi veya ID'ye göre ürün detayları.

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 {
            // hatayı işle
        }
    }
}

categoryId değiştiğinde, SwiftUI önceki isteği iptal eder ve yenisini başlatır. Bu, özellikle hızlı kategori geçişlerinde önemlidir — eski istekler durum güncellemesi için yenileriyle rekabet etmez. .task(id:) olmadan, değişiklikleri .onChange aracılığıyla manuel olarak izlemeniz ve Task'ı manuel olarak yönetmeniz gerekirdi.

Görev İptali ve isCancelled Kontrolü

.task View kaybolduğunda görevi otomatik olarak iptal etse de, asenkron işlemin kendisi iptali işbirlikçi bir şekilde kontrol etmelidir. Swift işbirlikçi bir iptal modeli kullanır — Task.cancel() yürütmeyi zorla durdurmaz, yalnızca isCancelled bayrağını ayarlar. Görev içindeki kod, bu bayrağı periyodik olarak kontrol etmelidir.

swift
struct LoadingView: View {
    @State var progress: Double = 0
    
    var body: some View {
        ProgressView(value: progress)
            .task {
                for i in 0..<100 {
                    // İptali kontrol et
                    try Task.checkCancellation()
                    
                    await Task.sleep(nanoseconds: 50_000_000)
                    progress = Double(i + 1) / 100.0
                }
            }
    }
}

Task.checkCancellation(), görev iptal edildiyse CancellationError fırlatır. Bu, kontrol etmenin en basit yoludur — herhangi bir async bağlamında çalışır. Bir alternatif, pahalı işlemlerden önce Task.isCancelled değerini manuel olarak kontrol etmektir. URLSession için, görev iptal edildiğinde ağ istekleri otomatik olarak iptal edilir, çünkü URLSession Structured Concurrency'yi yerel olarak destekler.

.task Pratik Örnekleri

.task birçok senaryo için uygundur: basit JSON yüklemeden TaskGroup ile karmaşık paralel işlemlere kadar. Üç tipik kullanım durumunu inceleyelim.

Hata Yönetimi ile Yükleme

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("Yükleme başarısız")
            }
        }
        .task {
            defer { isLoading = false }
            do {
                profile = await APIClient().fetchProfile()
            } catch {
                // profil nil kalır
            }
        }
    }
}

TaskGroup ile Paralel Yükleme

swift
struct DashboardView: View {
    @State var stats: DashboardStats?
    
    var body: some View {
        Text("Kontrol Paneli")
            .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
            }
    }
}

.task ile Sık Yapılan Hatalar

En yaygın hata, ana iş parçacığına geçmeden .task içinde UI özelliklerini değiştirmektir. SwiftUI async bağlamında @State değiştirirken otomatik olarak güncellemeleri ana iş parçacığına döndürse de, .task içinde UIKit öğelerinin doğrudan manipülasyonu çökmeye neden olabilir.

  • try/catch unutulması — .task hataları otomatik olarak işlemez. Hata fırlatan tüm işlevler do/catch içine sarılmalıdır, aksi takdirde uygulama çöker.
  • Yarış durumu — birden fazla .task(id:) farklı id'lerle başlatılırsa ve aynı durumu güncellerse, yarış durumları oluşabilir. Farklı veri kaynakları için ayrı özellikler kullanın.
  • Uzun senkron işlemler — .task senkron kodu asenkron yapmaz. .task içinde ağır senkron iş varsa, onu Task.detached içine sarın veya ayrı bir async yönteme taşıyın.
  • CancellationError'ı yok saymak — Task.checkCancellation() kontrol edilirken CancellationError yukarıya iletilmeli, bastırılmamalıdır. İptali bastırmak bellek sızıntılarına yol açabilir.
swift
// ❌ Hata: hata yönetimi yok
.task {
    let data = await fetchData() // hata oluştuğunda çöker!
    items = data
}

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

Sıkça Sorulan Sorular

.task ile .onAppear'da Task { } kullanmak arasındaki fark nedir?

.task, View kaybolduğunda görevi otomatik olarak iptal eder ve Structured Concurrency'yi destekler. .onAppear'daki Task { }, göreve manuel olarak referans tutmayı ve .onDisappear'da cancel() çağırmayı gerektirir. .task ayrıca okunması daha kolaydır — veri yüklemenin View yaşam döngüsünün bir parçası olduğunu açıkça belirtir.

.task bir publisher'a abone olmak için kullanılabilir mi?

Evet, bir AsyncSequence veya AsyncStream'e abone olmak için .task içinde for await value in publisher.values kullanın. Bu, Publisher.values uzantısı aracılığıyla hem async/await hem de Combine ile çalışır. View kaybolduğunda, yineleme otomatik olarak sona erer ve abonelik iptal edilir.

.task TabView ile nasıl çalışır — sekme değiştirildiğinde görev yeniden başlar mı?

Evet, TabView içindeki View her değişimde yeniden oluşturuluyorsa. iOS 18'den itibaren TabView, Views'ı bellekte tutabilir — bu durumda .task yeniden başlamaz. Her sekme değişiminde verileri yeniden yüklemeniz gerekiyorsa, sekme tanımlayıcısıyla .task(id:) kullanın.

.task içeren bir View, istek tamamlanmadan kaybolursa ne olur?

SwiftUI, View kaybolduğunda görevi iptal eder. URLSession isteği görevin içindeyse, o da iptal edilir. Görev işbirlikçi iptali desteklemiyorsa (örneğin, isCancelled'i kontrol etmiyorsa), çalışmaya devam eder, ancak sonucu duruma uygulanmaz çünkü View artık mevcut değildir.

Tek bir View'de birden fazla .task değiştiricisi kullanılabilir mi?

Evet, tek bir View'de birden fazla .task değiştiricisi ekleyebilirsiniz. Her biri bağımsız bir görev oluşturur. Bu, farklı veri kaynaklarını ayırmak için kullanışlıdır: profil yüklemek için bir .task, WebSocket'e abone olmak için ikincisi, coğrafi konumu izlemek için üçüncüsü.

Özet

  • .task { } — View kaybolduğunda otomatik iptal ile asenkron işlemler için SwiftUI değiştiricisi.
  • async/await desteği — .task içinde Task sarmalayıcısı olmadan tam async bağlamı kullanılabilir.
  • .task(id:) — tanımlayıcı değiştiğinde görevi yeniden başlatır, manuel .onChange'in yerini alır.
  • İşbirlikçi iptal — görev içinde iptali kontrol etmek için Task.checkCancellation() kullanın.
  • Structured Concurrency — .task, alt görevlerin iptali ile TaskGroup ve paralel işlemleri destekler.
  • .onAppear yerine — asenkron veri yükleme için .onAppear + Task + .onDisappear kalıbı yerine .task kullanın.
  • Hata yönetimi — çökmeleri önlemek için .task içindeki tüm async çağrıları do/catch ile sarılmalıdır.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun