Section 2/171 menit

2. Masalah yang Dipecahkan

2. Masalah yang Dipecahkan

Masalah: Kode Async yang "Bekerja" tapi Tidak Aman

Sebelum Swift Concurrency, kita menulis kode async dengan completion handler + DispatchQueue. Kode "bekerja" di test tapi punya race condition yang muncul di production tanpa peringatan.

swift
// ❌ TANPA isolation: race condition senyap
final class ImageCache {
    private var storage: [URL: UIImage] = [:]

    func image(for url: URL, completion: @escaping (UIImage?) -> Void) {
        if let cached = storage[url] {
            completion(cached)
            return
        }
        URLSession.shared.dataTask(with: url) { data, _, _ in
            let image = data.flatMap(UIImage.init)
            if let image {
                self.storage[url] = image  // ❌ Race: dipanggil dari banyak thread
            }
            completion(image)
        }.resume()
    }
}

Dengan Swift Concurrency + isolation, masalah ini menjadi compile error, bukan crash production.

swift
// ✓ DENGAN isolation: race ter-deteksi compiler
actor ImageCache {
    private var storage: [URL: UIImage] = [:]

    func image(for url: URL) async throws -> UIImage? {
        if let cached = storage[url] { return cached }
        let (data, _) = try await URLSession.shared.data(from: url)
        let image = UIImage(data: data)
        if let image { storage[url] = image }
        return image
    }
}

Masalah: Tidak Ada Konsistensi di Tim

Tanpa best practice yang disepakati tim:

  • Satu engineer pakai @MainActor everywhere → UI lag.
  • Satu engineer pakai actor untuk semua → over-engineering, banyak hop.
  • Satu engineer pakai @unchecked Sendable tanpa lock → data race senyap.

Materi ini menetapkan default kollektif yang masuk akal untuk tim.