Method Swizzling adalah fitur pada bahasa pemrograman Objective-C untuk mengganti implementasi dari selector yang sudah ada, pada saat runtime.
Atau sederhananya, dengan fitur tersebut kita bisa mengubah behavior dari suatu method ketika method tersebut dipanggil.
Misalnya kita punya method A, nah jika method A dipanggil, kita bisa mengubah agar code dari method B yang akan dijalankan, bukan code dari method A.
Dan karena bahasa pemrograman Objective-C dengan Swift itu interopable (bisa digunakan secara bersamaan), maka fitur tersebut juga bisa digunakan pada bahasa pemrograman Swift.
Berikut adalah beberapa contoh kasus mengapa kita memerlukan Method Swizzling:
1. Mengurangi kode yang redundan
Misalnya kita ingin agar semua UIViewController mempunyai background dengan warna kuning, nah dengan Method Swizzling, kita tidak perlu lagi untuk mengatur warna background di setiap UIViewController.
2. Memodifikasi implementasi pada method secara global
Katakanlah kita ingin agar semua data yang disimpan di UserDefaults, key nya harus memiliki prefix "XYZ_"
Cara yang biasa kita lakukan, mungkin adalah bikin aja satu function untuk menyimpan data ke UserDefaults yang akan menambahkan prefix "XYZ_" pada key nya, dan tiap kali kita ingin menyimpan data, kita tinggal gunakan function tersebut.
Namun cara tersebut punya masalah ketika ada Library yang juga menggunakan UserDefaults, Library tersebut tidak mungkin kan menggunakan function yang kita buat di atas?
Dalam kasus ini, kita bisa memecahkan masalah tersebut menggunakan Method Swizzling.
Perhatikan kode berikut:
1class Logger {2 func log(_ text: String) {3 print(text)4 }5}
Jika kita ingin mengganti implementasi method log ketika method tersebut dipanggil, kita harus menambahkan attribute @objc dan keyword dynamic pada method log.
1@objc dynamic func log(_ text: String) {
Kemudian kita buat implementasi baru dari method log, sebagai contoh kita akan menampilkan tanggal sebelum text log-nya :
1@objc dynamic func logWithDate(_ text: String) {2 print("\(Date()): \(text)")3}
Terakhir, kita buat sebuah method untuk melakukan Method Swizzling :
1static func swizzle() {2 let defaultMethod = class_getInstanceMethod(Self.self, #selector(log))3 let newMethod = class_getInstanceMethod(Self.self, #selector(logWithDate))45 if let defaultMethod = defaultMethod, let newMethod = newMethod {6 method_exchangeImplementations(defaultMethod, newMethod)7 print("log method swizzled!")8 }9}
class_getInstanceMethod digunakan untuk mendapatkan method yang ingin kita swizzle. class_getInstanceMethod menerima 2 paramater, yang pertama adalah class yang kita swizzle (Self me-refer ke Logger). dan parameter kedua adalah selector untuk method yang ingin kita swizzle.
Dan, jika kita jalankan code berikut:
1Logger.swizzle()23let logger = Logger()4logger.log("test...")
Output-nya akan seperti ini:
1log method swizzled!22023-02-11 18:40:17 +0000: test...
Bagaimana jika kita ingin agar implementasi default dari method log tetap terpanggil?
Caranya seperti ini:
1@objc dynamic func logWithDate(_ text: String) {2 print("\(Date()): \(text)")35 self.logWithDate(text)6}
1log method swizzled!22023-02-11 18:40:17 +0000: test...4test...
Kenapa kita justru memanggil self.logWithDate(text) bukannya self.log(text) ? Karena kedua method tersebut telah di-swap implementasinya.
Sekarang, kita akan coba mengubah warna background pada setiap UIViewController secara global menggunakan teknik Method Swizzling.
Caranya hampir sama dengan yang sebelumnya, bedanya kita akan membuat extension dari UIViewController seperti ini:
ViewController.swift1extension UIViewController {2 @objc dynamic func viewDidLoad2() {3 self.viewDidLoad2()45 view.backgroundColor = .systemYellow6 }78 static func swizzle() {9 let defaultMethod = class_getInstanceMethod(Self.self, #selector(viewDidLoad))10 let newMethod = class_getInstanceMethod(Self.self, #selector(viewDidLoad2))1112 if let defaultMethod = defaultMethod, let newMethod = newMethod {13 method_exchangeImplementations(defaultMethod, newMethod)14 }15 }16}
Lalu kita panggil method swizzle di AppDelegate
AppDelegate.swift1func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {3 UIViewController.swizzle()4 return true5}
Jalankan projectnya (⌘ + R), maka hasilnya akan seperti ini :
Jika kita melakukan Method Swizzling berkali-kali untuk method yang sama, maka Method Swizzling yang terakhir lah yang akan digunakan.
Jika ada framework yang juga menggunakan Method Swizzling, pastikan kita tidak melakukan Method Swizzling juga untuk method yang sama, karena bisa menyebabkan konflik.
Jika kita menggunakan Method Swizzling untuk sebuah framework yang akan digunakan oleh orang lain, pastikan kita menuliskannya di dokumentasi framework-nya.
Oke mungkin itu saja yang bisa saya bagikan kali ini, kalau kamu merasa artikel ini bermanfaat silakan Like & Share artikel ini ke teman-teman kamu atau jika kamu punya pertanyaan, tulis aja di kolom komentar, Thank you! 😁 🙏
Always open to new ideas. 🕊️
Articles that you might want to read.
Tanpa memanipulasi Javascript DOM
Menulis kode yang mudah untuk di-test pada Swift.
Tutorial membongkar dan memodifikasi aplikasi iOS 🍎