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