Method Swizzling হল একটি রানটাইম কৌশল যেখানে দুটি ক্লাস মেথডের বাস্তবায়ন নির্বাহের সময় অদলবদল করা হয়। এটি একটি সাবক্লাস তৈরি না করে বা সোর্স কোড পরিবর্তন না করে সিস্টেম মেথডের আচরণ ওভাররাইড বা সম্পূরক করার অনুমতি দেয়। এই কৌশলটি iOS ডেভেলপমেন্টে Objective-C-এর সাথে সর্বাধিক প্রয়োগ পেয়েছে, কিন্তু Kotlin/Android-এ reflection-এর মাধ্যমে অ্যানালগ বিদ্যমান। NSHipster Guide by Mattt, 2024 অনুসারে, swizzling হল Objective-C Runtime-এর সবচেয়ে শক্তিশালী কিন্তু সবচেয়ে বিপজ্জনক প্রক্রিয়াগুলির মধ্যে একটি।
মূল বিষয়
Method Swizzling হল একটি রানটাইম কৌশল যা দুটি Objective-C মেথডের বাস্তবায়ন অদলবদল করে। Swizzling-এর পরে, originalSelector কল করলে swizzledSelector-এর কোড নির্বাহিত হয়, এবং বিপরীতটিও সত্য। এটি Objective-C Runtime-এর স্থাপত্যের কারণে সম্ভব, যেখানে প্রতিটি সিলেক্টর (SEL) একটি ডিসপ্যাচ টেবিলের মাধ্যমে একটি বাস্তবায়নের (IMP) সাথে যুক্ত — একটি টেবিল যা নির্বাহের সময় পরিবর্তন করা যেতে পারে।
“swizzling” শব্দটি ২০০০-এর দশকের শুরুতে Cocoa ডেভেলপার সম্প্রদায়ে প্রবর্তিত হয়েছিল। কৌশলটি লাইব্রেরিগুলির জন্য ব্যাপক পরিচিতি লাভ করেছিল যেমন: AFNetworking (লোডিং ট্র্যাক করতে UIWebView-এর swizzling), Aspects (swizzling-ভিত্তিক AOP ফ্রেমওয়ার্ক) এবং FLEX (পরিদর্শনের জন্য সিস্টেম মেথড swizzle করা ডিবাগিং টুল)। আজ, swizzling বেশিরভাগ iOS অ্যাপ্লিকেশনে অন্তর্নিহিতভাবে — মনিটরিং এবং অ্যানালিটিক্স লাইব্রেরির মাধ্যমে ব্যবহৃত হয়।
Swizzling-এর একটি গুরুত্বপূর্ণ বৈশিষ্ট্য হল বৈশ্বিকতা: বাস্তবায়ন প্রতিস্থাপন ইনস্ট্যান্স স্তরে নয়, ক্লাস স্তরে ঘটে। যদি কোনো লাইব্রেরি UIViewController.viewDidLoad মেথড swizzle করে, এটি অ্যাপ্লিকেশনের UIViewController-এর সমস্ত ইনস্ট্যান্সকে প্রভাবিত করে, সিস্টেমেরগুলিকেও অন্তর্ভুক্ত করে। এটি একইসাথে swizzling-এর শক্তি — কোডের একটি লাইন পুরো অ্যাপ্লিকেশনের আচরণ পরিবর্তন করে — এবং বাগের মূল উৎস।
Objective-C Runtime প্রতিটি ক্লাসে একটি ডিসপ্যাচ টেবিল সংরক্ষণ করে — একটি অভিধান যেখানে কী হল SEL (মেথড আইডেন্টিফায়ার) এবং মান হল IMP (বাস্তবায়ন ফাংশনের পয়েন্টার)। যখন কোনো অ্যাপ্লিকেশন কোনো অবজেক্টে বার্তা পাঠায়, objc_msgSend এই টেবিলে রৈখিক অনুসন্ধান করে। Method Swizzling একটি SEL-এর IMP অন্য SEL-এর IMP দিয়ে প্রতিস্থাপন করে, কল পুনর্নির্দেশ করে।
// নিরাপদ method swizzling বাস্তবায়ন
@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
মূল ফাংশন হল method_exchangeImplementations(Method, Method)। এটি দুটি Method অবজেক্টের IMP পরমাণুভাবে অদলবদল করে। কলের পরে, ক্লাস ডিসপ্যাচ টেবিল পরিবর্তিত হয়: original কল করলে swizzled কোড নির্বাহিত হয়, swizzled কল করলে original কোড নির্বাহিত হয়। SafeSwizzle ক্যাটাগরি এই মেথডটি সমস্ত NSObject-এ যোগ করে, যেকোনো ক্লাসকে swizzling করার অনুমতি দেয়।
নিরাপদ swizzling বাস্তবায়নের জন্য swizzled সংস্করণের ভিতরে মূল বাস্তবায়ন কল করা প্রয়োজন। অন্যথায়, মেথডের মূল আচরণ স্থায়ীভাবে হারিয়ে যায়। সঠিক প্যাটার্ন হল অদলবদলের আগে মূল IMP সংরক্ষণ করা এবং swizzled মেথডে এটি কল করা:
// মূল বাস্তবায়ন কল সহ Swizzling
- (void)swizzled_viewDidLoad {
// 1. মূল বাস্তবায়ন কল করা
[self swizzled_viewDidLoad];
// 2. মূল কলের পরে অতিরিক্ত লজিক
NSLog("viewDidLoad নির্বাহিত, swizzling সক্রিয়");
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleClassMethod:@selector(viewDidLoad)
with:@selector(swizzled_viewDidLoad)];
});
}
dispatch_once গ্যারান্টি দেয় যে swizzling অ্যাপ্লিকেশনের জীবনকালে ঠিক একবার নির্বাহিত হয়। একই মেথড পুনরায় swizzling করলে অসীম পুনরাবৃত্তি হবে: swizzled মেথড নিজেকে কল করবে। +load ক্লাসটি রানটাইমে লোড হলে কল করা হয় — এটি swizzling-এর জন্য একটি নিরাপদ পয়েন্ট যা মূল অ্যাপ্লিকেশন কোডের আগে নির্বাহিত হয়।
একটি Objective-C ক্লাসের ডিসপ্যাচ টেবিল হল method_t স্ট্রাকচারের একটি অ্যারে যাতে SEL, IMP এবং রিটার্ন টাইপ থাকে। method_exchangeImplementations কেবল এই টেবিলে দুটি IMP পয়েন্টার অদলবদল করে। গুরুত্বপূর্ণ: swizzling শুধুমাত্র ক্লাস স্তরে কাজ করে, প্রোটোকল স্তরে নয়। যদি একটি মেথড প্রোটোকলে সংজ্ঞায়িত কিন্তু বাস্তবায়িত না হয়, ডিসপ্যাচ টেবিলে swizzling-এর জন্য কোনো এন্ট্রি থাকে না।
Swizzling ওভারহেড ন্যূনতম — ডিসপ্যাচ টেবিলে দুটি IMP পয়েন্টার অদলবদল করতে কয়েক ন্যানোসেকেন্ড সময় লাগে। Swizzling-এর পরে, মেথড ডিসপ্যাচ ধীর হয় না: objc_msgSend swizzling-এর আগের মতোই একই O(1) সময়ে IMP খুঁজে পায়। একমাত্র অতিরিক্ত অপারেশন হল অদলবদলের পরে প্রথম কলের সময় মেথড ক্যাশ চেক। Apple Performance Team-এর তথ্য অনুসারে, swizzling অ্যাপ্লিকেশনের কর্মক্ষমতাকে প্রভাবিত করে না।
Method Swizzling তিনটি মূল পরিস্থিতিতে ব্যবহৃত হয়: মনিটরিং এবং অ্যানালিটিক্স (স্বয়ংক্রিয় ইভেন্ট পাঠানোর জন্য viewDidLoad, viewDidAppear ট্র্যাকিং), AOP ইন্টারসেপশন (সমস্ত মেথড কলের প্যারামিটার লগ করা), এবং হটফিক্স (JSPatch-এর মতো লাইব্রেরির মাধ্যমে App Store Review ছাড়াই প্রোডাকশন বাগ ঠিক করা)।
এই প্রতিটি পরিস্থিতি কাজ করে কারণ swizzling কেন্দ্রীয়ভাবে প্রয়োগ করা হয়। একটি অ্যানালিটিক্স লাইব্রেরি +load-এ একবার swizzling করে, এবং অ্যাপ্লিকেশনের সমস্ত UIViewController ইনস্ট্যান্স ইভেন্ট পাঠানো শুরু করে। ডেভেলপারকে প্রতিটি কন্ট্রোলারে কোড যোগ করার প্রয়োজন নেই — এটি দ্বিগুণকরণ এবং ত্রুটির ঝুঁকি হ্রাস করে।
Android-এ, ক্লাসিক Objective-C অর্থে method swizzling অসম্ভব — Java/Kotlin vtable-এর মাধ্যমে স্ট্যাটিক ডিসপ্যাচ ব্যবহার করে। তবে, এমন প্রক্রিয়া বিদ্যমান যা অনুরূপ প্রভাব অর্জন করে: রানটাইম বাস্তবায়ন প্রতিস্থাপনের জন্য Java Reflection এবং বিল্ড সময় বাইটকোড পরিবর্তনের জন্য Gradle Transform API / ASM।
// Android-এ reflection + companion object-এর মাধ্যমে Swizzling
class Logger {
companion object {
var originalImpl: (() -> Unit)? = null
}
fun log() {
println("মূল লগ")
}
}
// রানটাইমে reflection-এর মাধ্যমে বাস্তবায়ন প্রতিস্থাপন
fun swizzleLog() {
val originalMethod = Logger::class.java
.getDeclaredMethod("log")
originalMethod.isAccessible = true
Logger.originalImpl = {
originalMethod.invoke(Logger())
}
// ইনলাইন ফাংশনের মাধ্যমে প্রতিস্থাপন
println("swizzled: লগ ইন্টারসেপ্ট করা হয়েছে")
}
এই কোডটি Java Reflection-এর মাধ্যমে log() মেথডের আচরণ পরিবর্তন করে: getDeclaredMethod প্রাইভেট বাস্তবায়ন অ্যাক্সেস করে, isAccessible অ্যাক্সেস চেক নিষ্ক্রিয় করে। সরাসরি log() কল করার পরিবর্তে, একটি র্যাপার কল করা হয় যা অতিরিক্ত লজিক নির্বাহ করে। তবে, Android JIT-এর মাধ্যমে হট মেথড অপ্টিমাইজ করে — reflection আগে থেকেই কম্পাইল করা AOT সেগমেন্টে কাজ নাও করতে পারে।
আরও নির্ভরযোগ্য পদ্ধতি হল ASM লাইব্রেরির সাথে Gradle Transform API বা AGP (Android Gradle Plugin)-এর মাধ্যমে বাইটকোড ম্যানিপুলেশন। বাইটকোড পরিবর্তন কম্পাইল সময়ে করা হয়: ASM ক্লাসের প্রতিটি মেথডে কল যোগ করে। এইভাবে কোড কভারেজ টুল (JaCoCo) এবং পারফরম্যান্স মনিটরিং টুল (Firebase Performance Monitoring) কাজ করে।
Method Swizzling একটি উচ্চ-ঝুঁকির কৌশল। লাইব্রেরিগুলির মধ্যে দ্বন্দ্ব: যদি দুটি লাইব্রেরি একই মেথড swizzle করে, নির্বাহের ক্রম নিশ্চিত নয়। iOS আপডেটের সাথে অসামঞ্জস্য: যদি Apple কোনো নতুন iOS সংস্করণে সিগনেচার পরিবর্তন করে বা মেথড মুছে দেয়, swizzling ক্র্যাশের কারণ হয়। কোডে দৃশ্যমানতার অভাব: swizzling ক্লাস বাস্তবায়নে দৃশ্যমান নয়, যা ডিবাগিং জটিল করে তোলে।
| ঝুঁকি | বর্ণনা | প্রশমন |
|---|---|---|
| লাইব্রেরি দ্বন্দ্ব | দুটি লাইব্রেরি viewDidAppear swizzle করে — একটি অন্যটি ভেঙে দেয় | class_getInstanceMethod-এর মাধ্যমে মেথডটি আগে থেকেই swizzled কিনা পরীক্ষা করুন |
| পুনরাবৃত্তি | একই মেথড পুনরায় swizzling করলে অসীম লুপ হয় | সর্বদা dispatch_once ব্যবহার করুন |
| সিগনেচার পরিবর্তন | Apple নতুন iOS-এ মেথড সিগনেচার পরিবর্তন করে — IMP অমিল | সমস্ত সমর্থিত iOS সংস্করণে পরীক্ষা করুন |
| অদৃশ্যতা | Swizzling Xcode কল স্ট্যাকে প্রদর্শিত হয় না | কোডে সমস্ত swizzling অপারেশন ডকুমেন্ট করুন |
| App Review | Apple নথিভুক্ত না করা swizzling সহ অ্যাপ্লিকেশন প্রত্যাখ্যান করে | শুধুমাত্র পাবলিক API ব্যবহার করুন এবং উদ্দেশ্য ডকুমেন্ট করুন |
সেরা অভ্যাস নিরাপদ swizzling-এর জন্য: সর্বদা মূল বাস্তবায়ন কল করুন, dispatch_once-এর মাধ্যমে +load-এ কঠোরভাবে swizzling করুন, swizzled মেথডগুলিকে উপসর্গ দিয়ে নাম দিন (যেমন, s_originalMethodName), প্রতিটি swizzling অপারেশন তার উদ্দেশ্য সহ ডকুমেন্ট করুন। Aspects লাইব্রেরি মূল মেথডের আগে/পরে ব্লকের শৃঙ্খলিত নির্বাহের মাধ্যমে দ্বন্দ্ব সমস্যা সমাধান করে।
Method swizzling-এর বিকল্প পূর্বাভাসযোগ্যতা এবং নিরাপত্তার কারণে প্রোডাকশন কোডের জন্য পছন্দনীয়। ডেলিগেট এবং প্রোটোকল (UIApplicationDelegate, UITableViewDelegate) রানটাইম পরিবর্তন না করেই স্পষ্ট এক্সটেনশন পয়েন্ট প্রদান করে। সাবক্লাসিং — viewDidAppear ওভাররাইড করে UIViewController-এর সাবক্লাস তৈরি করা — পূর্বাভাসযোগ্যভাবে কাজ করে এবং এর কোনো দ্বন্দ্ব নেই।
SwiftUI এবং Combine swizzling-এর প্রয়োজনীয়তা দূর করে: মডিফায়ার (onAppear, onChange) মেথড ওভাররাইড না করেই ঘোষণামূলকভাবে আচরণ যোগ করে। Android Jetpack Compose-এ প্রভাব (LaunchedEffect, SideEffect) এবং মডিফায়ারের মাধ্যমে একই অর্জিত হয়। AOP ফ্রেমওয়ার্ক (Android-এর জন্য AspectJ, iOS-এর জন্য InterposeKit) কম্পাইল-টাইম উইভিং সহ একটি নিরাপদ বিকল্প প্রদান করে।
Apple WWDC 2024-এর তথ্য অনুসারে, Swift রানটাইম ভাষা স্তরে method swizzling সমর্থন করে না — @objc dynamic মেথডগুলি শুধুমাত্র Objective-C Runtime-এর মাধ্যমে swizzled করা যেতে পারে। যে Swift অ্যাপ্লিকেশনগুলি @objc ব্যবহার করে না, তারা তৃতীয়-পক্ষের লাইব্রেরি দ্বারা আকস্মিক swizzling থেকে সম্পূর্ণ সুরক্ষিত। এটি Swift-কে আরও নিরাপদ করে কিন্তু রানটাইম ইন্সট্রুমেন্টেশন ক্ষমতা সীমিত করে।
SwiftUI মডিফায়ার (onAppear, onChange, onReceive) এবং Jetpack Compose প্রভাব (LaunchedEffect, SideEffect, DisposableEffect) UI কাজের জন্য swizzling সম্পূর্ণরূপে প্রতিস্থাপন করে। তারা ডিসপ্যাচ টেবিল পরিবর্তন না করেই ক্রস-কাটিং আচরণ যোগ করার একটি ঘোষণামূলক, পূর্বাভাসযোগ্য এবং পরীক্ষাযোগ্য উপায় প্রদান করে। নতুন প্রকল্পে, Apple এবং Google রানটাইম ইন্টারসেপশনের পরিবর্তে এই পদ্ধতির সুপারিশ করে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Method Swizzling প্রোডাকশনের জন্য গ্রহণযোগ্য যখন নিয়মগুলি অনুসরণ করা হয়: একবার নির্বাহের জন্য dispatch_once, মূল বাস্তবায়ন কল করা, সমস্ত iOS সংস্করণে পরীক্ষা এবং ডকুমেন্টেশন। সহজ কাজের জন্য, ডেলিগেট বা সাবক্লাসিং ব্যবহার করা ভাল। প্রোডাকশনে Swizzling মনিটরিং এবং অ্যানালিটিক্স লাইব্রেরির জন্য ন্যায়সঙ্গত।
Method Swizzling ডিসপ্যাচ টেবিলে IMP প্রতিস্থাপনের একটি নির্দিষ্ট কৌশল। AOP (পহেলা-ভিত্তিক প্রোগ্রামিং) একটি দৃষ্টান্ত যেখানে swizzling একটি প্রক্রিয়া হিসাবে ব্যবহার করা যেতে পারে। AOP-তে কম্পাইল-টাইম উইভিং (AspectJ), প্রক্সি-ভিত্তিক ইন্টারসেপশন (Spring AOP) এবং কোড জেনারেশনও অন্তর্ভুক্ত।
সমস্ত বার্তা ট্র্যাক করতে objc_msgSend-এ ব্রেকপয়েন্ট ব্যবহার করুন। ক্লাস নামের শর্ত সহ method_exchangeImplementations-এ একটি সিম্বলিক ব্রেকপয়েন্ট যোগ করুন। FLEX টুল দেখায় কোন ক্লাস মেথডগুলি swizzled। পদ্ধতিগত পরীক্ষার জন্য, lldb স্ক্রিপ্ট ব্যবহার করুন যা ক্লাসের ডিসপ্যাচ টেবিল আউটপুট করে।
Swift ভাষা স্তরে swizzling সমর্থন করে না। Method Swizzling শুধুমাত্র @objc dynamic চিহ্নিত মেথডগুলির জন্য কাজ করে, যা Objective-C Runtime-এর মাধ্যমে কম্পাইল হয়। বিশুদ্ধ Swift মেথডগুলি (@objc ছাড়া) স্ট্যাটিক ডিসপ্যাচ ব্যবহার করে এবং swizzled করা যাবে না — তাদের ডিসপ্যাচ টেবিল পরিবর্তনের জন্য অ্যাক্সেসযোগ্য নয়।
Firebase Analytics (স্বয়ংক্রিয় স্ক্রিন ট্র্যাকিংয়ের জন্য viewDidAppear-এর swizzling), Amplitude, Mixpanel, FLEX (UI পরিদর্শন), OHHTTPStubs (নেটওয়ার্ক অনুরোধ মকিং), Aspects (AOP ফ্রেমওয়ার্ক)। এগুলি সবই মূল বাস্তবায়ন কল সহ dispatch_once-এর মাধ্যমে +load-এ swizzling করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন