Section 12/161 menit

12. Troubleshooting Isolation Errors

12. Troubleshooting Isolation Errors

Error: "Passing argument of non-sendable type across actor boundaries"

swift
// Error: class non-Sendable dikirim ke actor lain
class UserSession {  // Non-Sendable
    var token: String = ""
}

actor AuthService {
    func validate(session: UserSession) async -> Bool {  // ❌ Error
        return !session.token.isEmpty
    }
}

// Solusi 1: Jadikan Sendable
final class UserSession: Sendable {  // final + Sendable — jika semua property Sendable
    let token: String  // let, bukan var — immutable
    init(token: String) { self.token = token }
}

// Solusi 2: Gunakan value type
struct UserSession: Sendable {
    var token: String
}

// Solusi 3: Kirim data yang diperlukan, bukan objeknya
actor AuthService {
    func validate(token: String) async -> Bool {  // Kirim String (Sendable), bukan objek
        return !token.isEmpty
    }
}

Error: "Actor-isolated property cannot be referenced from a non-isolated context"

swift
@MainActor
class ViewController {
    var items: [String] = []

    func setupTimer() {
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            // Timer callback bukan @MainActor — nonisolated
            // self?.items.append("tick")  // ❌ Error

            // Solusi: hop ke MainActor eksplisit
            Task { @MainActor [weak self] in
                self?.items.append("tick")  // ✓
            }
        }
    }
}

Error: "Cannot call actor-isolated function in a synchronous nonisolated context"

swift
actor DataService {
    func fetchData() -> [String] { [] }
}

// Error: panggil actor method dari sync context
let service = DataService()
// let data = service.fetchData()  // ❌ — harus dari async context

// Solusi 1: async context
func getDataAsync() async -> [String] {
    await service.fetchData()  // ✓
}

// Solusi 2: Task
func getDataWithTask() {
    Task {
        let data = await service.fetchData()
        print(data)
    }
}

Error: "Mutation of captured var in concurrently executing code"

swift
// Error: var di-capture oleh multiple closures yang bisa run concurrent
func processItems(_ items: [Int]) async {
    var results: [Int] = []

    await withTaskGroup(of: Int.self) { group in
        for item in items {
            group.addTask {
                // results.append(item * 2)  // ❌ Error: mutation dari concurrent tasks
                return item * 2
            }
        }
        for await result in group {
            results.append(result)  // ✓ — dikumpulkan serial di withTaskGroup
        }
    }
}

Checklist Debugging Isolation Error

swift
1. Error "non-sendable across boundary"?
    Cek apakah tipe bisa dijadikan Sendable (struct, final class, actor)
    Atau kirim hanya data yang diperlukan (bukan seluruh objek)
    Atau gunakan nonisolated(unsafe) dengan jaminan manual

2. Error "actor-isolated from non-isolated context"?
    Pastikan caller ada di async context (tambah async/await)
    Atau bungkus dengan Task { @MainActor in ... }

3. Error "mutation captured var concurrent"?
    Kumpulkan hasil di akhir TaskGroup, bukan mutate di dalam task
    Atau gunakan actor sebagai accumulator

4. Error "sending non-Sendable value"?
    Cek apakah nilai masih diakses setelah dikirim
    Atau jadikan nilai Sendable
    Atau pisahkan lifecycle: buat, kirim, jangan gunakan lagi

5. Tidak ada error tapi ada race condition di runtime?
    Audit semua suspension point (await) dalam actor
    Pastikan invariant state valid setelah setiap await
    Gunakan state machine untuk operasi kompleks