15. Kapan Tidak Digunakan
15. Kapan Tidak Digunakan
❌ Actor untuk Data Stateless
Kalau "actor" kamu tidak punya state mutable, gunakan struct atau function. Actor punya overhead executor; tidak ada gunanya tanpa state.
// ❌ Overkill
actor URLBuilder {
func build(_ host: String, _ path: String) -> URL { /* ... */ }
}
// ✓
enum URLBuilder {
static func build(_ host: String, _ path: String) -> URL { /* ... */ }
}
❌ MainActor untuk Pure Computation
Computation berat (parsing, image processing, encryption) jangan di-@MainActor. UI akan freeze.
// ❌
@MainActor
final class Parser {
func parseAllRecords(_ data: Data) -> [Record] { /* CPU-heavy */ }
}
// ✓ — non-isolated atau di actor lain
final class Parser: Sendable {
func parseAllRecords(_ data: Data) -> [Record] { /* CPU-heavy */ }
}
❌ @unchecked Sendable Tanpa Synchronization
Pernyataan ke compiler "saya tahu yang saya lakukan". Kalau tidak ada lock/atomic/immutable di dalamnya, kamu tidak tahu yang kamu lakukan.
❌ Custom Executor untuk "Performance"
Default executor sudah sangat dioptimalkan. Ganti hanya kalau punya alasan spesifik (integrasi dengan API legacy, hardware queue). Custom executor sering memperburuk performa karena meng-bypass work-stealing.
❌ Actor untuk Singleton "Karena Sekalian"
Singleton yang read-only setelah init lebih baik jadi let global di-Sendable. Actor menambah hop untuk akses yang sebenarnya sync-safe.
❌ MainActor.run di Setiap Closure UIKit
Kalau closure dipanggil oleh UIKit dari main thread, gunakan MainActor.assumeIsolated — MainActor.run selalu hop.
// ❌ Hop yang tidak perlu
button.addAction(UIAction { _ in
Task { await MainActor.run { self.handle() } } // hop walau sudah di main
})
// ✓
button.addAction(UIAction { _ in
MainActor.assumeIsolated { self.handle() } // tanpa hop
})