Tüm Yazılar
KategoriSwift
Okuma Süresi
24 dk
Yayın Tarihi
...
Kelime Sayısı
1.641kelime

Kahveni hazırla - bu içerikli bir makale!

Swift'in Actor modeli, global actors, Sendable protocol, structured concurrency, AsyncStream ve data race safety'yi derinlemesine öğrenin.

Swift Concurrency ve Actors: Thread Safety Garantisi

Thread safety, multi-threaded programlamanın en zor problemidir. Data race'ler sinsi bug'lardır — bazen çalışır, bazen crash eder, genellikle debug'ı imkansızdır. Swift 5.5 ile gelen Actor modeli, bu sorunu dil seviyesinde çözer. Swift 6 ile birlikte ise data race safety varsayılan olarak zorunlu hale geliyor.

💡 Hızlı Not: Bu rehber WWDC21-24 Concurrency session'ları ve Swift Evolution proposal'larından derlendi. Swift 6 strict concurrency dahil.

İçindekiler

  1. Actor Model Nedir?
  2. Actor Tanımlama ve Kullanma
  3. Global Actors: @MainActor
  4. Sendable Protocol ve Data Race Safety
  5. Actor Isolation
  6. Structured Concurrency: Task Groups
  7. AsyncStream ve AsyncSequence
  8. Continuations: Callback'ten Async'e
  9. Actor Reentrancy
  10. Swift 6 Data Race Safety

Actor Model Nedir? {#actor-model}

Actor, mutable state'i koruyan ve concurrent erişimi serialize eden bir reference type'dır. Class'a benzer ama built-in thread safety ile gelir:

swift
1// ❌ Class - data race riski
2class UnsafeCounter {
3 var count = 0
4 func increment() { count += 1 } // Thread-unsafe!
5}
6 
7// ✅ Actor - thread-safe garanti
8actor SafeCounter {
9 var count = 0
10 func increment() { count += 1 } // Actor-isolated
11}
12 
13// Actor kullanımı - await gerekli
14let counter = SafeCounter()
15await counter.increment() // Async erişim
16let value = await counter.count

Actor vs Class vs Struct

Özellik
Actor
Class
Struct
Reference/Value
Reference
Reference
Value
Thread safety
✅ Built-in
❌ Manual
✅ (immutable)
Mutable state
✅ Güvenli
⚠️ Data race
✅ Copy-on-write
Inheritance
❌ Yok
✅ Var
❌ Yok
async erişim
Gerekli
Gerekli değil
Gerekli değil

Actor Tanımlama ve Kullanma {#actor-kullanim}

swift
1actor ImageCache {
2 private var cache: [URL: UIImage] = [:]
3 private let maxSize: Int
4 
5 init(maxSize: Int = 100) {
6 self.maxSize = maxSize
7 }
8 
9 func get(_ url: URL) -> UIImage? {
10 cache[url]
11 }
12 
13 func set(_ image: UIImage, for url: URL) {
14 if cache.count >= maxSize {
15 // LRU eviction
16 cache.removeValue(forKey: cache.keys.first!)
17 }
18 cache[url] = image
19 }
20 
21 // nonisolated - actor isolation'ı gerektirmeyen computed property
22 nonisolated var description: String {
23 "ImageCache(maxSize: \(maxSize))"
24 }
25}
26 
27// Kullanım
28let cache = ImageCache()
29if let cached = await cache.get(imageURL) {
30 display(cached)
31} else {
32 let image = try await downloadImage(from: imageURL)
33 await cache.set(image, for: imageURL)
34 display(image)
35}

Global Actors: @MainActor {#global-actors}

@MainActor, UI güncellemelerinin main thread'de yapılmasını garanti eder:

swift
1// Tüm class main thread'de çalışır
2@MainActor
3class UserViewModel: ObservableObject {
4 @Published var user: User?
5 @Published var isLoading = false
6 
7 func loadUser() async {
8 isLoading = true // Main thread ✅
9 
10 // Network call - otomatik background'a geçer
11 let user = try? await fetchUser()
12 
13 self.user = user // Main thread ✅
14 isLoading = false // Main thread ✅
15 }
16}
17 
18// Sadece tek fonksiyon
19class DataProcessor {
20 func processData() async -> [Result] {
21 // Background thread'de ağır işlem
22 let results = await heavyComputation()
23 
24 // UI güncelleme için MainActor'a geç
25 await MainActor.run {
26 updateUI(with: results)
27 }
28 
29 return results
30 }
31}

Sendable Protocol ve Data Race Safety {#sendable}

Sendable, bir değerin concurrent context'ler arasında güvenle paylaşılabileceğini belirtir:

swift
1// ✅ Otomatik Sendable - struct with Sendable properties
2struct UserDTO: Sendable {
3 let id: UUID
4 let name: String
5 let email: String
6}
7 
8// ✅ Actor - otomatik Sendable
9actor SessionManager: Sendable {
10 var token: String?
11}
12 
13// ❌ Class - Sendable değil (mutable reference type)
14class UserManager {
15 var users: [User] = [] // Data race riski!
16}
17 
18// ✅ @Sendable closure
19func performInBackground(_ work: @Sendable () async -> Void) {
20 Task { await work() }
21}
22 
23// ✅ @unchecked Sendable - manuel thread safety garanti ediyorsan
24final class ThreadSafeArray<Element>: @unchecked Sendable {
25 private var array: [Element] = []
26 private let lock = NSLock()
27 
28 func append(_ element: Element) {
29 lock.lock()
30 defer { lock.unlock() }
31 array.append(element)
32 }
33}

Structured Concurrency: Task Groups {#structured-concurrency}

swift
1// Paralel API çağrıları
2func loadDashboard() async throws -> Dashboard {
3 async let profile = fetchProfile()
4 async let orders = fetchOrders()
5 async let recommendations = fetchRecommendations()
6 
7 return try await Dashboard(
8 profile: profile,
9 orders: orders,
10 recommendations: recommendations
11 )
12}
13 
14// TaskGroup ile dinamik sayıda paralel iş
15func downloadImages(urls: [URL]) async throws -> [UIImage] {
16 try await withThrowingTaskGroup(of: (Int, UIImage).self) { group in
17 for (index, url) in urls.enumerated() {
18 group.addTask {
19 let (data, _) = try await URLSession.shared.data(from: url)
20 return (index, UIImage(data: data)!)
21 }
22 }
23 
24 var images: [(Int, UIImage)] = []
25 for try await result in group {
26 images.append(result)
27 }
28 
29 return images.sorted(by: { $0.0 < $1.0 }).map(\.1)
30 }
31}

AsyncStream ve AsyncSequence {#async-stream}

swift
1// AsyncStream ile continuous data
2func locationUpdates() -> AsyncStream<CLLocation> {
3 AsyncStream { continuation in
4 let manager = CLLocationManager()
5 let delegate = LocationDelegate { location in
6 continuation.yield(location)
7 }
8 manager.delegate = delegate
9 manager.startUpdatingLocation()
10 
11 continuation.onTermination = { _ in
12 manager.stopUpdatingLocation()
13 }
14 }
15}
16 
17// Kullanım
18for await location in locationUpdates() {
19 updateMap(with: location)
20}

Continuations: Callback'ten Async'e {#continuations}

swift
1// Callback-based API'yi async'e çevir
2func fetchImage(url: URL) async throws -> UIImage {
3 try await withCheckedThrowingContinuation { continuation in
4 URLSession.shared.dataTask(with: url) { data, _, error in
5 if let error {
6 continuation.resume(throwing: error)
7 } else if let data, let image = UIImage(data: data) {
8 continuation.resume(returning: image)
9 } else {
10 continuation.resume(throwing: ImageError.invalidData)
11 }
12 }.resume()
13 }
14}
⚠️ Kritik: Continuation tam olarak bir kez resume edilmeli. Sıfır kez = memory leak, iki kez = crash!

Actor Reentrancy {#reentrancy}

Actor'lar reentrant'tır — bir await noktasında başka bir çağrı actor'a girebilir:

swift
1actor BankAccount {
2 var balance: Double = 1000
3 
4 func withdraw(_ amount: Double) async -> Bool {
5 guard balance >= amount else { return false }
6 // ⚠️ await sonrası balance değişmiş olabilir!
7 balance -= amount
8 return true
9 }
10}
11// İki concurrent withdraw: ikisi de guard'ı geçebilir!
12// Çözüm: await'ten sonra tekrar kontrol et

Swift 6 Data Race Safety {#swift-6}

Swift 6'da -strict-concurrency varsayılan olarak aktif. Tüm data race'ler compile error:

swift
1// Swift 6'da bu compile etmez:
2class Counter {
3 var value = 0 // ❌ Sendable değil, concurrent erişim unsafe
4}
5 
6// Çözümler:
7actor Counter { var value = 0 } // ✅ Actor
8struct Counter: Sendable { let value: Int } // ✅ Immutable struct

Concurrency Performans ve Debug İpuçları

Concurrency sorunlarını tespit etmek ve çözmek için kullanabileceğin araçlar ve teknikler:

swift
1// 1. Task priority kullanarak iş önceliği belirle
2Task(priority: .userInitiated) {
3 // Kullanıcı etkileşimi - yüksek öncelik
4 await loadProfile()
5}
6 
7Task(priority: .background) {
8 // Arka plan işi - düşük öncelik
9 await syncAnalytics()
10}
11 
12// 2. Task cancellation'ı doğru kullan
13class SearchViewModel: ObservableObject {
14 private var searchTask: Task<Void, Never>?
15 
16 func search(query: String) {
17 // Önceki aramayı iptal et
18 searchTask?.cancel()
19 searchTask = Task {
20 try? await Task.sleep(for: .milliseconds(300))
21 guard !Task.isCancelled else { return }
22 let results = try? await api.search(query: query)
23 guard !Task.isCancelled else { return }
24 await MainActor.run { self.results = results ?? [] }
25 }
26 }
27}
28 
29// 3. Custom global actor tanımla
30@globalActor
31actor DatabaseActor: GlobalActor {
32 static let shared = DatabaseActor()
33}
34 
35// Tüm database işlemleri bu actor'da çalışır
36@DatabaseActor
37class DatabaseService {
38 func save(_ item: Item) async throws {
39 // Bu fonksiyon DatabaseActor'da serialize edilir
40 }
41}

Concurrency Debugging Araçları

Araç
Kullanım
Nasıl Aktifleştirilir
**Thread Sanitizer (TSan)**
Data race tespiti
Scheme > Diagnostics > Thread Sanitizer
**Instruments: Swift Concurrency**
Task yaşam döngüsü takibi
Instruments > Swift Concurrency template
**SWIFT_DETERMINISTIC_HASHING**
Deterministik test sonuçları
Environment variable olarak ekle
**Strict Concurrency Checking**
Compile-time data race uyarıları
Build Settings > Complete
⚠️ Debug İpucu: Thread Sanitizer aktifken uygulamanın 2-10x yavaşladığını unutma. Sadece debug build'lerde kullan, release build'e asla ekleme.

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var: **Kaynaklar:** - [WWDC21: Protect mutable state with Swift actors](https://developer.apple.com/videos/play/wwdc2021/10133/) - [WWDC22: Eliminate data races using Swift Concurrency](https://developer.apple.com/videos/play/wwdc2022/110351/) - [SE-0306: Actors](https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md) - [Swift 6 Migration Guide](https://www.swift.org/migration/documentation/migrationguide/)

Etiketler

#swift#concurrency#actors#async-await#sendable#thread-safety#structured-concurrency
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

Bunu da begenebilirsiniz