Giriş

Swift 5.5 ile birlikte gelen async/await, iOS geliştirme dünyasında callback ve completion handler cehenneminden kurtulmanın en temiz yolu haline geldi. Bu yazıda gerçek dünya senaryolarıyla Swift Concurrency’yi ele alacağız.

Neden async/await?

Klasik completion handler yaklaşımının sorunları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// ❌ Eski yöntem — callback cehennemi
func fetchUser(id: String, completion: @escaping (Result<User, Error>) -> Void) {
    networkService.get("/users/\(id)") { result in
        switch result {
        case .success(let data):
            do {
                let user = try JSONDecoder().decode(User.self, from: data)
                self.fetchPosts(for: user) { postsResult in
                    // Bir kat daha içeriye...
                }
            } catch {
                completion(.failure(error))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ✅ async/await ile temiz kod
func fetchUser(id: String) async throws -> User {
    let data = try await networkService.get("/users/\(id)")
    return try JSONDecoder().decode(User.self, from: data)
}

func loadUserWithPosts(id: String) async throws -> (User, [Post]) {
    let user = try await fetchUser(id: id)
    let posts = try await fetchPosts(for: user)
    return (user, posts)
}

Structured Concurrency ile Paralel İşlemler

İki bağımsız network isteğini paralel yapmak için async let kullanın:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func loadDashboard() async throws -> Dashboard {
    async let user = fetchUser(id: currentUserID)
    async let notifications = fetchNotifications()
    async let feed = fetchFeed()

    // Üçü paralel çalışır, hepsi bitince devam eder
    return Dashboard(
        user: try await user,
        notifications: try await notifications,
        feed: try await feed
    )
}

TaskGroup ile Dinamik Paralellik

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func fetchAllPosts(ids: [String]) async throws -> [Post] {
    try await withThrowingTaskGroup(of: Post.self) { group in
        for id in ids {
            group.addTask {
                try await self.fetchPost(id: id)
            }
        }

        var posts: [Post] = []
        for try await post in group {
            posts.append(post)
        }
        return posts
    }
}

Actor ile Thread Safety

Shared mutable state’i güvenli hale getirmek için actor kullanın:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
actor UserCache {
    private var cache: [String: User] = [:]

    func user(for id: String) -> User? {
        cache[id]
    }

    func store(_ user: User, for id: String) {
        cache[id] = user
    }
}

// Kullanım
let cache = UserCache()
await cache.store(user, for: user.id)
let cachedUser = await cache.user(for: id)

MainActor ile UI Güncellemeleri

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@MainActor
class ProfileViewModel: ObservableObject {
    @Published var user: User?
    @Published var isLoading = false

    func loadProfile() async {
        isLoading = true
        defer { isLoading = false }

        do {
            user = try await userService.fetchCurrentUser()
        } catch {
            // Hata yönetimi
        }
    }
}

Sonuç

Swift Concurrency, iOS kodunu hem okunabilir hem de hata yapmaya karşı dayanıklı hale getiriyor. async/await, actor ve TaskGroup üçlüsünü kullanarak modern, güvenli ve performanslı uygulamalar yazabilirsiniz.

Bir sonraki yazıda AsyncStream ve AsyncSequence konularına değineceğiz.