Bab 1: Swift Memory & Value vs Reference Type Mutability π§
Mengenal perbedaan fundamental tipe penyimpanan memori Stack vs Heap, serta konsep mutabilitas Value vs Reference Types di Swift.
Penjelasan Kelas Bayi πΌ
Value Type (`Struct`) itu seperti membagikan lembar kertas tugas cetak. Ketika temanmu menggambar kumis kucing di kertasnya, kertas tugas milikmu tidak akan berubah sama sekali karena kamu memegang kertas fisik yang berbeda!
Reference Type (`Class`) itu seperti kamu dan temanmu berbagi link edit Google Docs yang sama. Siapapun yang mencoret-coret isinya, dokumennya akan berubah secara langsung untuk kalian semua!
Detail Alokasi Memori Stack vs Heap:
| Aspek | Value Type (Struct / Enum / Array) | Reference Type (Class / Closure) |
|---|---|---|
| Lokasi Memori | Stack (Cepat, otomatis dihapus saat keluar scope) | Heap (Fleksibel, diatur oleh ARC/referensi) |
| Penyalinan | Menyalin data asli secara penuh (Copy-on-Assignment) | Menyalin alamat memorinya saja (Shared Instance) |
| Mutability | Variabel penampung harus `var` agar bisa diubah. Jika `let`, compiler akan menolak. | Bisa diubah walaupun objek ditampung dalam `let` karena pointernya yang konstan. |
Jebakan Soal: Struct di dalam Class (Nesting Mutability)
Kasus Khusus: Jika kamu memasukkan Struct di dalam Class, misalnya class `Carrier` memiliki variabel `point` yang bertipe struct `Point`.
Saat kamu menyalin pointer class `var c2 = c1`, modifikasi pada properties struct di `c2` (contoh: `c2.point.x = 20`) **akan ikut mengubah** `c1.point.x` menjadi 20! Kenapa?
Karena struct tersebut terbungkus di dalam wadah reference type yang sama di Heap. Jadi, perubahan dari sisi mana pun akan tercermin di referensi bersama!
Bab 2: Loop Tracing, Modulo & Bitwise Operator XOR π
Membaca perulangan bersarang (nested loops), operator sisa bagi (MOD), dan operasi logika biner Bitwise XOR.
Penjelasan Kelas Bayi πΌ
Nested Loop itu seperti putaran jarum jam. Jarum menit (loop dalam) harus menyelesaikan putaran penuh terlebih dahulu, baru jarum jam (loop luar) bisa melangkah 1 langkah maju.
XOR (Exclusive OR) adalah permainan setuju/tidak setuju: Jika kedua bitnya **berbeda** (1 dan 0), nilainya **1** (setuju). Tapi jika bitnya **sama** (0 dan 0, atau 1 dan 1), nilainya **0** (tidak setuju)!
Modulo & Bitwise XOR (Eksklusif-OR):
- Operator Modulo (`MOD` atau `%`): Sisa hasil pembagian bulat.
Contoh: `5 MOD 2 = 1` (karena 5 dibagi 2 adalah 2, sisa 1). `4 MOD 2 = 0` (habis dibagi/genap). - Bitwise XOR: Membandingkan biner bit demi bit.
Konversikan angka desimal ke biner terlebih dahulu:
- Angka 5 → `0101`
- Angka 3 → `0011`
Bandingkan setiap kolom bit:
- Bit 1: `0 XOR 0 = 0`
- Bit 2: `1 XOR 0 = 1`
- Bit 3: `0 XOR 1 = 1`
- Bit 4: `1 XOR 1 = 0`
Hasil biner: `0110` → Desimalnya adalah **6**!
Tracing Nested Loops:
Gunakan **Trace Table** agar tidak salah menjumlahkan variabel `total` di lembar coretan:
DECLARE total, o, i AS INTEGER
SET total = 0
FOR o = 1 TO 3 DO
FOR i = 1 TO 2 DO
IF (o + i) MOD 2 == 0 THEN
total = total + (o * 2)
ELSE
total = total + i
ENDIF
ENDFOR
ENDFOR
Bongkar putaran satu per satu: ketika `o=1`, jalankan `i=1` (o+i = 2, genap → total + 2), lalu `i=2` (o+i = 3, ganjil → total + i = total + 2). Lakukan hal yang sama untuk `o=2` dan `o=3`!
Bab 3: Pilar OOP, Inheritance & Protocol Extensions π§±
Menguasai 4 pilar pemrograman berorientasi objek, method overriding, dan dynamic dispatch pada protocol extensions.
Penjelasan Kelas Bayi πΌ
Inheritance itu seperti bayi mewarisi nama keluarga dan bakat bernyanyi dari ayahnya. Tapi, saat bayi bernyanyi, dia bisa bernyanyi dengan nadanya sendiri yang lebih tinggi (meng-override suara ayah). Namun, jika dia mau, dia juga bisa bernyanyi bersama ayahnya (`super.sapa()`)!
4 Pilar OOP & Method Overriding:
- Encapsulation: Membatasi akses langsung dengan properti `private` serta menyediakan `getters`/`setters`.
- Inheritance: Kelas anak (`subclass`) mewarisi sifat kelas induk (`superclass`).
- Polymorphism: Kemampuan satu method nama sama untuk berperilaku berbeda pada tipe objek berbeda.
- Abstraction: Menyembunyikan kerumitan di balik antarmuka sederhana (seperti `Protocol` di Swift).
- Method Overriding & `super`: Saat subclass menulis ulang method induk menggunakan kata kunci `override`. Panggilan `super.sapa()` akan menjalankan method milik induk terlebih dahulu sebelum melanjutkan ke baris berikutnya di method anak.
Dynamic Dispatch di Protocol Extensions:
Swift mengizinkan protocol memiliki implementasi default via extension:
protocol Sapaan { func halo() }
extension Sapaan { func halo() { print("Halo Protocol") } }
struct Orang: Sapaan { func halo() { print("Halo Orang") } }
let user: Sapaan = Orang()
user.halo() // Mencetak: "Halo Orang"
Karena method `halo()` terdaftar di dalam cetak biru protocol utama, Swift menggunakan **Dynamic Dispatch** untuk memanggil implementasi kustom milik objek asli di runtime (`Orang`), bukan default extension-nya. Hasilnya, method kustom struct selalu menang!
Bab 4: Swift Optionals, Arrays & Nil Coalescing π
Memahami cara aman mengambil nilai array, membuka kado data optional, dan menggunakan operator fallback `??`.
Penjelasan Kelas Bayi πΌ
Optionals itu seperti kotak kado misterius. Kadonya bisa berisi mainan mobil-mobilan (nilai nyata), atau bisa juga kosong melongpong (`nil`).
Nil Coalescing `??` adalah ban pelampung darurat: "Buka kadonya, jika kosong (`nil`), gunakan mainan cadangan di sebelah kanan!"
Array Indexing & Nil Coalescing:
- Zero-based Array Index: Indeks laci array dimulai dari **0**, bukan 1!
Contoh: `let angka = [10, 20, 30]`. Untuk mengambil 30, gunakan indeks `angka[2]`. - Optional Declaration: Ditandai dengan tanda tanya (contoh: `var namaOpt: String?`).
- Nil Coalescing Operator (`??`):
Sintaks: `let hasil = nilaiOptional ?? nilaiDefault`
Jika `nilaiOptional` bernilai `nil`, maka `hasil` akan mengambil `nilaiDefault`.
Contoh Kasus Tracing Ujian:
var namaOpt: String? = nil
var namaDefault = "Budi"
let finalName = namaOpt ?? namaDefault
// finalName = "Budi" karena namaOpt kosong (nil).
Ingat! Operator `??` adalah cara paling ringkas dan aman untuk menghindari aplikasi crash saat membuka kado data opsional di Swift.
Bab 5: Closure Capture Lists, Rekursi & Memory Cycle πΈ
Memahami tumpukan pemanggilan fungsi rekursif, snapshot capture list pada closure, dan penanganan kebocoran memori ARC.
Penjelasan Kelas Bayi πΌ
Closure Capture List `[nilai]` itu seperti memotret angka di papan tulis dengan kamera polaroid. Walaupun papan tulisnya kemudian dihapus dan diganti angka baru, foto polaroid di tanganmu tetap menampilkan angka yang lama!
Rekursi itu seperti membuka boneka Rusia Matryoshka yang di dalamnya ada boneka lebih kecil, terus sampai boneka terkecil habis, baru kita tutup satu per satu kembali.
Detail Rekursi & Capture List:
- Fungsi Rekursif: Fungsi yang memanggil dirinya sendiri. Wajib memiliki base case (kondisi henti) agar tidak terjadi stack overflow.
Contoh tracing `faktorial(3)`: `3 * faktorial(2)` → `3 * (2 * faktorial(1))` → `3 * 2 * 1 = 6`. - Capture List `[variabel]`:
Menyalin nilai variabel secara instan saat closure dideklarasikan.
Jika tanpa `[nilai]`, closure akan mereferensikan variabel asli sehingga mencetak 20.var nilai = 10 let printNilai = { [nilai] in print(nilai) } nilai = 20 printNilai() // Mencetak 10! (Salinan snapshot)
ARC & Retain Cycle (Memory Leak):
Jika dua class saling merujuk secara kuat (`strong`), mereka tidak akan pernah dihapus dari memori RAM meskipun variabel penampungnya sudah di-set ke `nil`. Ini dinamakan **Retain Cycle**.
Solusi: Tambahkan kata kunci `weak` atau `unowned` pada salah satu deklarasi variabel agar rantai penguncian referensi terputus otomatis!
Bab 6: SwiftUI, Big O & Higher-Order Functions π
Memahami paradigma deklaratif SwiftUI, cara mengukur efisiensi algoritma dengan Big O, dan memanfaatkan map/filter/reduce untuk kode yang elegan.
Penjelasan Kelas Bayi πΌ
SwiftUI itu seperti memesan makanan di restoran β kamu cukup bilang "saya mau nasi goreng" (deklaratif), bukan ikut ke dapur menjelaskan cara menggorengnya (imperatif seperti UIKit)!
Big O itu seperti membandingkan dua kurir: Kurir A selalu tiba dalam 10 menit (O(1), tidak peduli beratnya). Kurir B makin lama kalau paketnya makin banyak (O(n)). Pilih kurir yang paling efisien!
Big O Notation β Urutan dari Tercepat ke Terlambat:
| Notasi | Nama | Contoh Nyata |
|---|---|---|
| O(1) | Konstan | Akses array via index: arr[3] |
| O(log n) | Logaritmik | Binary Search (belah dua setiap langkah) |
| O(n) | Linear | Loop satu kali dari awal ke akhir array |
| O(n log n) | Linearitmik | Merge Sort, Quick Sort efisien |
| O(nΒ²) | Kuadratik | Nested loop (loop dalam loop) |
SwiftUI Property Wrappers & Higher-Order Functions:
@State: Sumber kebenaran (source of truth) lokal milik view. Ubah nilainya β view otomatis re-render.
Contoh:@State var count = 0βButton { count += 1 }@Binding: Referensi dua arah ke@Statemilik parent view. Anak bisa baca & ubah data induk.
Parent:@State var nama = ""β Child:@Binding var nama: String.map { }: Transformasi setiap elemen β array baru.
[1,2,3].map { $0 * 2 }β[2, 4, 6].filter { }: Saring elemen berdasarkan kondisi β array subset.
[1,2,3,4].filter { $0 % 2 == 0 }β[2, 4].reduce(initial) { }: Gabungkan semua elemen menjadi satu nilai.
[1,2,3].reduce(0, +)β6
Keunggulan SwiftUI vs UIKit:
| Aspek | SwiftUI (Deklaratif) | UIKit (Imperatif) |
|---|---|---|
| Cara kerja | Tulis apa yang ingin ditampilkan | Tulis bagaimana cara menampilkan |
| Preview | Live preview di Xcode Canvas β | Harus run simulator β |
| Platform | iOS, macOS, watchOS, tvOS sekaligus | Hanya iOS/iPadOS |
| Jumlah kode | Jauh lebih sedikit (ringkas) | Lebih verbose (panjang) |
Tip ujian: Untuk project baru β pilih SwiftUI. UIKit masih relevan untuk project lama atau fitur kompleks yang belum di-support SwiftUI.