Method Swizzling — runtime texnikasi bo‘lib, unda sinfning ikki metodining implementatsiyalari bajarish vaqtida joylarini almashtiradi. U pastki sinf yaratmasdan va manba kodini o‘zgartirmasdan tizim metodining xatti-harakatini bekor qilish yoki kengaytirish imkonini beradi. Texnika eng ko‘p Objective-C da iOS dasturida qo‘llanilgan, ammo Kotlin/Android da reflection orqali o‘xshashlari mavjud. NSHipster Guide by Mattt, 2024 ma'lumotlariga ko‘ra, swizzling Objective-C Runtime ning eng kuchli, ammo eng xavfli mexanizmlaridan biridir.
Asosiy
Method Swizzling — ikki Objective-C metodining implementatsiyalarini bajarish vaqtida joylarini almashtiradigan runtime texnikasi. Swizzling dan so'ng originalSelector chaqiruvi swizzledSelector kodining bajarilishiga olib keladi va aksincha. Bu Objective-C Runtime arxitekturasi tufayli mumkin, bunda har bir selektor (SEL) dispatch table — bajarish vaqtida o‘zgartirilishi mumkin bo‘lgan jadval orqali implementatsiya (IMP) bilan bog‘langan.
«Swizzling» atamasi 2000-yillarning boshlarida Cocoa dasturchilari jamoasida kiritilgan. Texnika kutubxonalar tufayli keng tanildi: AFNetworking (yuklashni kuzatish uchun UIWebView swizzling), Aspects (swizzling ga asoslangan AOP framework) va FLEX (tekshirish uchun tizim metodlarini swizzle qiladigan disk raskadrovka vositasi). Bugun swizzling ko‘pchilik iOS ilovalarida bilvosita — monitoring va analitika kutubxonalari orqali qo‘llaniladi.
Swizzling ning muhim xususiyati — globallik: implementatsiyani almashtirish instansiya emas, sinf darajasida sodir bo‘ladi. Agar kutubxona UIViewController.viewDidLoad metodini swizzle qilsa, bu ilovadagi BARCHA UIViewController instansiyalariga, shu jumladan tizim instansiyalariga ta'sir qiladi. Bu bir vaqtning o‘zida swizzling ning kuchi — bir satr kod butun ilovaning xatti-harakatini o‘zgartiradi — va xatolarning asosiy manbai.
Objective-C Runtime har bir sinfda dispatch table — kaliti SEL (metod identifikatori), qiymati IMP (implementatsiya funksiyasiga ko‘rsatgich) bo‘lgan lug‘atni saqlaydi. Ilova ob'ektga xabar yuborganda, objc_msgSend ushbu jadvalda chiziqli qidirishni amalga oshiradi. Method Swizzling bir SEL ning IMP sini boshqa SEL ning IMP si bilan almashtirib, chaqiruvlarni yo'naltiradi.
// Xavfsiz method swizzling implementatsiyasi
@implementation NSObject (SafeSwizzle)
+ (void)swizzleClassMethod:(SEL)original
with:(SEL)swizzled {
Class cls = [self class];
SEL originalSel = original;
SEL swizzledSel = swizzled;
Method originalMethod = class_getInstanceMethod(cls, originalSel);
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSel);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
@end
Asosiy funksiya — method_exchangeImplementations(Method, Method). U ikkita Method ob'ektining IMP sini atom tarzda almashtiradi. Chaqiruvdan so'ng sinfning dispatch table i o'zgaradi: original ga murojaat qilganda swizzled kodi, swizzled ga murojaat qilganda esa original kodi bajariladi. SafeSwizzle kategoriyasi ushbu metodni barcha NSObject ga qo'shib, istalgan sinfga swizzling ni bajarish imkonini beradi.
Xavfsiz swizzling implementatsiyasi swizzled versiyasi ichida original implementatsiyani chaqirishni talab qiladi. Aks holda metodning original xatti-harakati qaytarib bo'lmaydigan darajada yo'qoladi. To'g'ri namuna — almashishdan oldin original IMP ni saqlash va uni swizzled-metodda chaqirish:
// Original implementatsiyani chaqirish bilan swizzling
- (void)swizzled_viewDidLoad {
// 1. Original implementatsiyani chaqirish
[self swizzled_viewDidLoad];
// 2. Original chaqiruvdan keyin qo'shimcha mantiq
NSLog("viewDidLoad bajarildi, swizzling faol");
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleClassMethod:@selector(viewDidLoad)
with:@selector(swizzled_viewDidLoad)];
});
}
dispatch_once swizzling ilovaning ishlash muddati davomida bir marta bajarilishini kafolatlaydi. Xuddi shu metodni qayta swizzle qilish cheksiz rekursiyaga olib keladi: swizzled metod o'zini-o'zi chaqiradi. +load sinf runtime ga yuklanganda chaqiriladi — bu ilovaning asosiy kodidan oldin bajariladigan swizzling uchun xavfsiz nuqta.
Objective-C dispatch table — SEL, IMP va qaytariladigan qiymat turini o'z ichiga olgan method_t strukturalari massivi. method_exchangeImplementations shunchaki ushbu jadvalda ikkita IMP ko'rsatgichini almashtiradi. Muhim: swizzling faqat sinf darajasida ishlaydi, protokol darajasida emas. Agar metod protokolda aniqlangan, lekin implementatsiya qilinmagan bo'lsa — dispatch table swizzling uchun yozuvni o'z ichiga olmaydi.
Swizzling ning yuki minimal — dispatch table da ikkita IMP ko'rsatgichini almashtirish bir necha nanosekund davom etadi. Swizzling dan keyin metod chaqiruvi sekinlashmaydi: objc_msgSend IMP ni swizzling dan oldingi kabi O(1) vaqtda topadi. Yagona qo'shimcha operatsiya — almashishdan keyin birinchi chaqiruvda method cache ni tekshirish. Apple Performance Team ma'lumotlariga ko'ra, swizzling ilovaning unumdorligiga ta'sir qilmaydi.
Method Swizzling uchta asosiy stsenariyda qo'llaniladi: monitoring va analitika (avtomatik hodisalarni jo'natish uchun viewDidLoad, viewDidAppear ni kuzatish), AOP tutib olish (metodning barcha chaqiruvlari parametrlarini qayd etish) va hotfix (JSPatch kabi kutubxonalar orqali App Store Review siz production da xatoni tuzatish).
Ushbu stsenariylarning har biri swizzling markazlashtirilgan holda qo'llanilishi tufayli ishlaydi. Analitika kutubxonasi +load da bir marta swizzling ni bajaradi va ilovadagi barcha UIViewController hodisalarni jo'natishni boshlaydi. Dasturchi har bir kontrollerda kod qo'shishi shart emas — bu takrorlanishni va xato xavfini kamaytiradi.
Android da klassik Objective-C ma'nosida method swizzling mumkin emas — Java/Kotlin vtable orqali statik dispetcherizatsiyadan foydalanadi. Biroq, shunga o'xshash effektga erishadigan mexanizmlar mavjud: runtime da implementatsiyani almashtirish uchun Java Reflection va qurish bosqichida baytkodni o'zgartirish uchun Gradle Transform API / ASM.
// Android da reflection + companion object orqali swizzling
class Logger {
companion object {
var originalImpl: (() -> Unit)? = null
}
fun log() {
println("original log")
}
}
// Runtime da reflection orqali implementatsiyani almashtirish
fun swizzleLog() {
val originalMethod = Logger::class.java
.getDeclaredMethod("log")
originalMethod.isAccessible = true
Logger.originalImpl = {
originalMethod.invoke(Logger())
}
// Inline funksiya orqali almashtirish
println("swizzled: log tutib olindi")
}
Bu kod Java Reflection orqali log() metodining xatti-harakatini o'zgartiradi: getDeclaredMethod xususiy implementatsiyaga kirishni oladi, isAccessible kirishni tekshirishni o'chiradi. To'g'ridan-to'g'ri log() chaqiruvi o'rniga qo'shimcha mantiqni bajaradigan o'rovchi chaqiriladi. Biroq, Android issiq metodlarni JIT orqali optimallashtiradi — reflection allaqachon kompilyatsiya qilingan AOT qismlarida ishlamasligi mumkin.
Ishonchliroq yondashuv — ASM kutubxonasi bilan Gradle Transform API yoki AGP (Android Gradle Plugin) orqali bytecode manipulation. Baytkodni o'zgartirish kompilyatsiya bosqichida amalga oshiriladi: ASM sinfning har bir metodiga chaqiruvlarni qo'shadi. Kod qamrovi vositalari (JaCoCo) va unumdorlik monitoringi (Firebase Performance Monitoring) shunday ishlaydi.
Method Swizzling — yuqori xavfli texnika. Kutubxonalar o'rtasidagi to'qnashuvlar: agar ikki kutubxona bir xil metodni swizzle qilsa, bajarish tartibi kafolatlanmaydi. iOS yangilanishlari bilan mos kelmaslik: Apple yangi iOS versiyasida imzoni o'zgartirsa yoki metodni o'chirsa, swizzling ishdan chiqishga olib keladi. Kodda ko'rinmaslik: swizzling sinf implementatsiyasida ko'rinmaydi, bu disk raskadrovkani qiyinlashtiradi.
| Xatar | Tavsif | Kamaytirish |
|---|---|---|
| Kutubxona to'qnashuvi | Ikki kutubxona viewDidAppear ni swizzle qiladi — biri ikkinchisini buzadi | Metod allaqachon swizzle qilinganligini class_getInstanceMethod orqali tekshiring |
| Rekursiya | Xuddi shu metodni qayta swizzle qilish cheksiz aylanishga sabab bo'ladi | Har doim dispatch_once dan foydalaning |
| Imzo o'zgarishi | Apple yangi iOS da metod imzosini o'zgartiradi — IMP mos kelmaydi | Barcha qo'llab-quvvatlanadigan iOS versiyalarida test qiling |
| Ko'rinmaslik | Swizzling Xcode chaqiruv stekida ko'rsatilmaydi | Barcha swizzling operatsiyalarini kodda hujjatlashtiring |
| App Review | Apple hujjatlashtirilmagan swizzling bilan ilovalarni rad etadi | Faqat ommaviy API lardan foydalaning va maqsadni hujjatlashtiring |
Best practices xavfsiz swizzling uchun quyidagilarni o'z ichiga oladi: har doim original implementatsiyani chaqiring, swizzling ni +load da dispatch_once orqali bajaring, swizzled-metodlarni prefiks bilan nomlang (masalan, s_originalMethodName), har bir swizzling operatsiyasini maqsadini ko'rsatib hujjatlashtiring. Aspects kutubxonasi to'qnashuvlar muammosini original metoddan oldin/keyin bloklarni zanjirli bajarish orqali hal qiladi.
Method swizzling ga alternativlar bashorat qilish mumkinligi va xavfsizligi sababli production kodi uchun afzalroqdir. Delegatlar va protokollar (UIApplicationDelegate, UITableViewDelegate) runtime ni o'zgartirmasdan aniq kengaytirish nuqtalarini ta'minlaydi. Pastki sinflar — viewDidAppear ni bekor qilish bilan UIViewController pastki sinfini yaratish — bashorat qilish mumkin bo'lgan tarzda ishlaydi va to'qnashuvlarga ega emas.
SwiftUI va Combine swizzling ga bo'lgan ehtiyojni yo'q qiladi: modifikatorlar (onAppear, onChange) metodlarni bekor qilmasdan deklarativ tarzda xatti-harakat qo'shadi. Android Jetpack Compose da xuddi shu effektga effektlar (LaunchedEffect, SideEffect) va modifikatorlar orqali erishiladi. AOP frameworklari (Android uchun AspectJ, iOS uchun InterposeKit) compile-time weaving bilan xavfsiz alternativani ta'minlaydi.
Apple WWDC 2024 ma'lumotlariga ko'ra, Swift runtime til darajasida method swizzling ni qo'llab-quvvatlamaydi — @objc dynamic metodlar faqat Objective-C Runtime orqali swizzle qilinishi mumkin. @objc dan foydalanmaydigan Swift ilovalari uchinchi tomon kutubxonalari tomonidan tasodifiy swizzling dan to'liq himoyalangan. Bu Swift ni xavfsizroq qiladi, ammo runtime instrumentalizasiya imkoniyatlarini cheklaydi.
SwiftUI modifikatorlari (onAppear, onChange, onReceive) va Jetpack Compose effektlari (LaunchedEffect, SideEffect, DisposableEffect) UI vazifalari uchun swizzling ni to'liq almashtiradi. Ular dispatch table ni o'zgartirmasdan kesishuvchi xatti-harakat qo'shishning deklarativ, bashorat qilish mumkin bo'lgan va tekshiriladigan usulini ta'minlaydi. Yangi loyihalarda Apple va Google runtime tutib olish o'rniga aynan shu yondashuvni tavsiya qiladi.
Tez-tez so'raladigan savollar
Method Swizzling qoidalarga rioya qilingan holda production uchun maqbuldir: bir martalik bajarish uchun dispatch_once, original implementatsiyani chaqirish, barcha iOS versiyalarida test qilish va hujjatlashtirish. Oddiy vazifalar uchun delegatlar yoki pastki sinflardan foydalanish yaxshiroqdir. Production da Swizzling monitoring va analitika kutubxonalari uchun asoslanadi.
Method Swizzling — dispatch table da IMP ni almashtirishning aniq texnikasi. AOP (Aspect-Oriented Programming) — swizzling mexanizmlardan biri sifatida ishlatilishi mumkin bo'lgan paradigmadir. AOP shuningdek compile-time weaving (AspectJ), proxy-ga asoslangan tutib olish (Spring AOP) va code generation ni o'z ichiga oladi.
Barcha xabarlarni kuzatish uchun objc_msgSend da breakpoint dan foydalaning. Sinf nomi sharti bilan method_exchangeImplementations ga ramziy breakpoint qo'shing. FLEX vositasi sinfning qaysi metodlari swizzle qilinganligini ko'rsatadi. Tizimli tekshirish uchun sinfning dispatch table ini ko'rsatadigan lldb skriptidan foydalaning.
Swift til darajasida swizzling ni qo'llab-quvvatlamaydi. Method Swizzling faqat @objc dynamic bilan belgilangan, Objective-C Runtime orqali kompilyatsiya qilinadigan metodlar uchun ishlaydi. Sof Swift metodlari (@objc holda) statik dispetcherizatsiyadan foydalanadi va swizzle qilinishi mumkin emas — ularning dispatch table i o'zgartirish uchun mavjud emas.
Firebase Analytics (avtomatik ekran kuzatuvi uchun viewDidAppear swizzling), Amplitude, Mixpanel, FLEX (UI tekshiruvi), OHHTTPStubs (tarmoq so'rovlarini moklash), Aspects (AOP framework). Hammasi original implementatsiyani chaqirish bilan dispatch_once orqali +load da swizzling ni bajaradi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.