Section 2/131 menit

2. Teori & Cara Kerja Internal

2. Teori & Cara Kerja Internal

Observation Framework

@Observable adalah Swift macro yang diperkenalkan di Swift 5.9 (Xcode 15, iOS 17) sebagai bagian dari framework Observation — bukan Combine. Framework ini murni Swift, tidak bergantung pada Objective-C runtime atau Combine.

Ekspansi Macro

Ketika kita menulis:

swift
@Observable
class UserViewModel {
    var name: String = ""
    var age: Int = 0
}

Swift macro meng-expand kode tersebut menjadi kira-kira:

swift
class UserViewModel: Observable {
    // Setiap property yang di-observe dibungkus dengan
    // akses ke _$observationRegistrar secara otomatis.

    @ObservationIgnored
    private var _name: String = ""

    var name: String {
        get {
            // Registrar mencatat: "siapa pun yang sedang mengakses,
            // daftarkan dirimu sebagai subscriber untuk property 'name'"
            _$observationRegistrar.access(keyPath: \.name)
            return _name
        }
        set {
            // Registrar memberitahu semua subscriber bahwa 'name' akan berubah
            _$observationRegistrar.withMutation(keyPath: \.name) {
                _name = newValue
            }
        }
    }

    @ObservationIgnored
    private var _age: Int = 0

    var age: Int {
        get {
            _$observationRegistrar.access(keyPath: \.age)
            return _age
        }
        set {
            _$observationRegistrar.withMutation(keyPath: \.age) {
                _age = newValue
            }
        }
    }

    // Registrar ini adalah "pusat kendali" observasi.
    // Ia menyimpan mapping: keyPath → Set<Observer>
    @ObservationIgnored
    private let _$observationRegistrar = ObservationRegistrar()
}

Mekanisme Dependency Tracking Otomatis

Ini adalah perbedaan paling fundamental antara @Observable dan ObservableObject:

swift
ObservableObject:
  View subscribe ke OBJECT → satu property berubah → VIEW DI-RENDER ULANG

@Observable:
  View membaca property X → SwiftUI MENCATAT bahwa View ini bergantung pada X
  Property Y berubah → SwiftUI cek: "apakah ada View yang bergantung pada Y?" → tidak ada → View TIDAK di-render ulang
  Property X berubah → SwiftUI cek: "ada View yang bergantung pada X?" → ada → View DI-RENDER ULANG

Dependency tracking ini terjadi secara otomatis saat runtime berdasarkan property mana yang dibaca di dalam body View. Tidak perlu anotasi manual.

swift
@Observable
class DashboardViewModel {
    var userName: String = "Ari"
    var postCount: Int = 42
    var followerCount: Int = 1000
    var isLoading: Bool = false
}

// View ini HANYA membaca userName dan postCount.
// SwiftUI mencatat dependensi: [userName, postCount]
// Ketika isLoading atau followerCount berubah → View ini TIDAK di-render ulang.
struct HeaderView: View {
    var viewModel: DashboardViewModel

    var body: some View {
        VStack {
            Text(viewModel.userName)   // → dependency: userName
            Text("\(viewModel.postCount) posts")  // → dependency: postCount
        }
    }
}

ObservationRegistrar

ObservationRegistrar adalah struct internal yang menjadi jantung dari Observation framework. Ia:

  1. Merekam akses (access): saat property dibaca, registrar mencatat siapa observer-nya
  2. Memicu mutasi (withMutation): saat property ditulis, registrar memberitahu semua observer yang bergantung pada property tersebut
  3. Menyimpan mapping per-keyPath: [PartialKeyPath<T>: Set<AnyObserver>]