Section 10/131 menit
10. Troubleshooting & Common Mistakes
10. Troubleshooting & Common Mistakes
Kesalahan 1: Sendable Violation
swift
// ERROR: 'NonSendableType' cannot be sent to actor-isolated method
class Config { // class biasa, tidak Sendable
var timeout: Int = 30
}
actor Service {
func configure(with config: Config) { } // ERROR di Swift 6
}
// Solusi A: jadikan struct (paling direkomendasikan)
struct Config: Sendable {
var timeout: Int = 30
}
// Solusi B: jadikan final + immutable + Sendable
final class Config: Sendable {
let timeout: Int
init(timeout: Int) { self.timeout = timeout }
}
// Solusi C: pindahkan logika ke dalam actor
actor Service {
var timeout: Int = 30
func setTimeout(_ value: Int) {
timeout = value
}
}
Kesalahan 2: Actor Reentrancy Bug
swift
actor Inventory {
var stock: [String: Int] = ["item_A": 5]
// BUGGY: reentrancy bisa menyebabkan overselling
func purchase(item: String) async -> Bool {
guard let count = stock[item], count > 0 else { return false }
await processPayment() // suspension point!
stock[item]! -= 1 // stock mungkin sudah 0 saat ini
return true
}
// BENAR: modifikasi state sebelum suspension
func purchaseSafe(item: String) async -> Bool {
guard let count = stock[item], count > 0 else { return false }
stock[item]! -= 1 // kurangi dulu sebelum await
await processPayment()
return true
}
private func processPayment() async {
try? await Task.sleep(for: .milliseconds(100))
}
}
Kesalahan 3: Deadlock dengan Actor + DispatchQueue
swift
// JANGAN lakukan ini — bisa deadlock
actor MyActor {
func doWork() {
DispatchQueue.main.sync { // ❌ sync dari actor bisa deadlock!
// update UI
}
}
// BENAR: gunakan await MainActor.run
func doWorkCorrectly() async {
await MainActor.run {
// update UI — aman
}
}
}
Kesalahan 4: Task.detached Tanpa Perlu
swift
@MainActor
class VC: UIViewController {
func loadData() {
// HINDARI:
Task.detached {
let data = await fetchData()
await MainActor.run { self.display(data) }
}
// LEBIH BAIK:
Task {
let data = await fetchData()
display(data) // otomatis di @MainActor
}
}
}
Kesalahan 5: Mengabaikan Task Cancellation
swift
actor DataFetcher {
func fetchLargeDataset() async throws -> [String] {
var results: [String] = []
for i in 0..<1000 {
// SELALU cek cancellation di loop panjang
try Task.checkCancellation()
let item = await fetchItem(at: i)
results.append(item)
}
return results
}
private func fetchItem(at index: Int) async -> String {
try? await Task.sleep(for: .milliseconds(10))
return "item_\(index)"
}
}