Section 2/161 menit
2. Masalah yang Dipecahkan
2. Masalah yang Dipecahkan
Masalah 1: Akses Bersamaan ke Shared State
swift
// ❌ TANPA data race safety: crash atau corruption di runtime
class UserCache {
var cache: [String: User] = [:] // mutable shared state
func store(_ user: User, forKey key: String) {
cache[key] = user // Thread A bisa baca saat Thread B write
}
func user(forKey key: String) -> User? {
return cache[key] // undefined behavior jika concurrent
}
}
// Dua thread memanggil ini bersamaan → crash
let userCache = UserCache()
DispatchQueue.global().async { userCache.store(user1, forKey: "a") }
DispatchQueue.global().async { userCache.store(user2, forKey: "b") }
swift
// ✓ DENGAN actor: compiler melarang akses bersamaan
actor UserCache {
private var cache: [String: User] = [:]
func store(_ user: User, forKey key: String) {
cache[key] = user // hanya satu akses pada satu waktu
}
func user(forKey key: String) -> User? {
return cache[key]
}
}
// Compiler memaksa penggunaan await
let userCache = UserCache()
await userCache.store(user1, forKey: "a")
await userCache.store(user2, forKey: "b") // serialized, tidak ada race
Masalah 2: Closure yang Capture Mutable State
swift
// ❌ TANPA data race safety: closure escape membawa mutable reference
class ViewModel {
var items: [Item] = []
func loadItems() {
URLSession.shared.dataTask(with: url) { [self] data, _, _ in
// ❌ self adalah class — bisa diakses dari thread lain bersamaan
self.items = parseItems(from: data!) // data race!
}.resume()
}
}
swift
// ✓ DENGAN @MainActor + Sendable: compiler enforce sinkronisasi
@MainActor
class ViewModel: ObservableObject {
@Published var items: [Item] = []
func loadItems() {
Task {
// Task secara explicit inherit isolation @MainActor
let data = try await URLSession.shared.data(from: url).0
// Parsing di background (nonisolated context)
let parsed = await Task.detached { parseItems(from: data) }.value
// Update UI di main actor
self.items = parsed // safe: hanya @MainActor yang bisa akses
}
}
}
Masalah 3: Non-Sendable Type Lolos ke Async Context
swift
// ❌ TANPA Sendable enforcement: UIKit objects dikirim ke background thread
func processImage() {
let image = UIImage(named: "photo")! // UIImage: non-Sendable, main-thread only
Task.detached {
// Swift 6: ERROR — UIImage bukan Sendable, tidak boleh crossing isolation boundary
let processed = applyFilter(to: image)
}
}
swift
// ✓ DENGAN Sendable design: hanya kirim data yang aman
func processImage() {
let image = UIImage(named: "photo")!
// Convert ke Sendable representation sebelum crossing boundary
guard let imageData = image.pngData() else { return }
Task.detached {
// Data adalah Sendable — aman untuk di-pass ke task terpisah
let processedData = applyFilter(to: imageData)
await MainActor.run {
// Kembali ke main actor untuk update UI
let result = UIImage(data: processedData)
updateUI(with: result)
}
}
}