ऑब्जेक्टिव-सी में मेथड स्विजलिंग के खतरे क्या हैं?


235

मैंने लोगों को यह कहते सुना है कि विधि का प्रयोग एक खतरनाक अभ्यास है। यहां तक ​​कि नाम स्वाज़लिंग से पता चलता है कि यह एक धोखा है।

मेथड स्विज़लिंग मैपिंग को संशोधित कर रहा है ताकि चयनकर्ता ए को कॉल करना वास्तव में कार्यान्वयन बी होगा। इसका एक उपयोग बंद स्रोत वर्गों के व्यवहार का विस्तार करना है।

क्या हम जोखिमों को औपचारिक रूप दे सकते हैं ताकि जो कोई भी निर्णय ले रहा है कि स्वीज़िंग का उपयोग करना है वह एक सूचित निर्णय ले सकता है कि क्या यह इसके लायक है कि वे क्या करने की कोशिश कर रहे हैं।

उदाहरण के लिए

  • नामकरण टकराव : यदि बाद में वर्ग ने आपके द्वारा जोड़े गए विधि का नाम शामिल करने के लिए अपनी कार्यक्षमता बढ़ा दी है, तो यह समस्याओं का एक बड़ा कारण होगा। सूजने वाले तरीकों का नामकरण करके जोखिम को कम करें।

यह पहले से ही बहुत अच्छा नहीं है कि आप अपने द्वारा पढ़े गए कोड से कुछ और प्राप्त करें
मार्टिन बाबाकेव

यह एक अशुद्ध तरीके की तरह लगता है कि अजगर डेकोरेटर बहुत सफाई से क्या करते हैं
क्लाउडी

जवाबों:


439

मुझे लगता है कि यह वास्तव में बहुत अच्छा सवाल है, और यह शर्म की बात है कि असली सवाल से निपटने के बजाय, अधिकांश जवाबों ने इस मुद्दे को छोड़ दिया है और बस कहा कि स्विज़लिंग का उपयोग न करें।

सिज़लिंग विधि का उपयोग करना रसोईघर में तेज चाकू का उपयोग करने जैसा है। कुछ लोग तेज चाकू से डरते हैं क्योंकि उन्हें लगता है कि वे खुद को बुरी तरह से काट लेंगे, लेकिन सच्चाई यह है कि तेज चाकू सुरक्षित हैं

बेहतर, अधिक कुशल, अधिक अनुरक्षण कोड लिखने के लिए विधि स्विज़लिंग का उपयोग किया जा सकता है। इसका दुरुपयोग भी हो सकता है और भयानक कीड़े हो सकते हैं।

पृष्ठभूमि

सभी डिज़ाइन पैटर्न के साथ, यदि हम पैटर्न के परिणामों से पूरी तरह अवगत हैं, तो हम इसका उपयोग करने या न करने के बारे में अधिक सूचित निर्णय लेने में सक्षम हैं। सिंगलटन एक ऐसी चीज़ का एक अच्छा उदाहरण है जो बहुत विवादास्पद है, और अच्छे कारण के लिए - वे वास्तव में ठीक से लागू करने के लिए कठिन हैं। कई लोग अभी भी सिंगलटन का उपयोग करना चुनते हैं, हालाँकि। यही बात स्वाज़लिंग के बारे में भी कही जा सकती है। एक बार अच्छी और बुरी दोनों बातों को समझने के बाद आपको अपनी राय बनानी चाहिए।

विचार-विमर्श

यहाँ विधि स्वाइलिंग के कुछ नुकसान हैं:

  • विधि स्वाज़लिंग परमाणु नहीं है
  • गैर-स्वामित्व वाले कोड का व्यवहार बदलता है
  • संभव नामकरण संघर्ष
  • स्विज़लिंग से विधि की दलीलें बदल जाती हैं
  • स्विज़ल्स का क्रम मायने रखता है
  • समझने में मुश्किल (पुनरावर्ती दिखता है)
  • डिबग करना मुश्किल है

ये बिंदु सभी मान्य हैं, और उन्हें संबोधित करते हुए हम परिणाम को प्राप्त करने के लिए उपयोग की जाने वाली पद्धति के साथ-साथ झूलने की हमारी समझ में सुधार कर सकते हैं। मैं हर एक को एक समय पर ले जाऊंगा।

विधि स्वाज़लिंग परमाणु नहीं है

मुझे अभी तक पद्धति के कार्यान्वयन को देखना है, जो समवर्ती 1 का उपयोग करने के लिए सुरक्षित है । यह वास्तव में 95% मामलों में एक समस्या नहीं है जिसे आप विधि स्विज़लिंग का उपयोग करना चाहते हैं। आमतौर पर, आप बस एक विधि के कार्यान्वयन को बदलना चाहते हैं, और आप चाहते हैं कि कार्यान्वयन आपके कार्यक्रम के पूरे जीवनकाल के लिए उपयोग किया जाए। इसका मतलब है कि आपको अपने तरीके से स्वीमिंग करनी चाहिए +(void)loadloadवर्ग विधि अपने आवेदन के शुरू में क्रमानुसार निष्पादित किया जाता है। यदि आप यहाँ अपनी स्विज़लिंग करते हैं, तो आपके पास कोई समस्या नहीं होगी। यदि आप +(void)initializeमें झपकी लेना चाहते थे , हालांकि, आप अपने झपट्टा कार्यान्वयन में एक दौड़ की स्थिति के साथ समाप्त हो सकते हैं और रनटाइम एक अजीब स्थिति में समाप्त हो सकता है।

गैर-स्वामित्व वाले कोड का व्यवहार बदलता है

यह एक मुद्दा है, जिसमें झूलों के साथ है, लेकिन यह पूरे बिंदु की तरह है। लक्ष्य उस कोड को बदलने में सक्षम होना है। इसका कारण यह है कि लोग इसे एक बड़ी बात बताते हैं क्योंकि आप केवल एक चीज के लिए चीजों को नहीं बदल रहे हैं, जिसके लिए NSButtonआप चीजों को बदलना चाहते हैं, बल्कि NSButtonअपने आवेदन में सभी उदाहरणों के लिए। इस कारण से, जब आप झपकी लेते हैं, तो आपको सतर्क रहना चाहिए, लेकिन आपको इसे पूरी तरह से बचने की आवश्यकता नहीं है।

इसे इस तरह से सोचें ... यदि आप किसी वर्ग में एक विधि को ओवरराइड करते हैं और आप सुपर क्लास पद्धति को नहीं कहते हैं, तो आपको समस्याएँ उत्पन्न हो सकती हैं। ज्यादातर मामलों में, सुपर क्लास उम्मीद कर रहा है कि विधि को बुलाया जाएगा (जब तक कि अन्यथा दस्तावेज न किया जाए)। यदि आप इसी विचार को ज़ोर से लागू करते हैं, तो आपने अधिकांश मुद्दों को कवर कर लिया है। हमेशा मूल कार्यान्वयन को कॉल करें। यदि आप नहीं करते हैं, तो आप शायद सुरक्षित होने के लिए बहुत अधिक बदल रहे हैं।

संभव नामकरण संघर्ष

पूरे कोको में नामकरण संघर्ष एक मुद्दा है। हम अक्सर श्रेणियों में श्रेणी के नाम और विधि के नाम उपसर्ग करते हैं। दुर्भाग्य से, नामकरण संघर्ष हमारी भाषा में एक प्लेग है। हालांकि, झूलों के मामले में, वे होना जरूरी नहीं है। हमें बस उस तरीके को बदलने की ज़रूरत है, जो हम विधि के बारे में सोचते हैं कि थोड़ा सा चक्कर लगा लें। सबसे अधिक इस तरह से किया जाता है:

@interface NSView : NSObject
- (void)setFrame:(NSRect)frame;
@end

@implementation NSView (MyViewAdditions)

- (void)my_setFrame:(NSRect)frame {
    // do custom work
    [self my_setFrame:frame];
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:@selector(my_setFrame:)];
}

@end

यह ठीक काम करता है, लेकिन अगर my_setFrame:कहीं और परिभाषित किया जाता है तो क्या होगा ? यह समस्या स्वाइलिंग के लिए अद्वितीय नहीं है, लेकिन हम इसके आसपास भी काम कर सकते हैं। वर्कअराउंड में अन्य नुकसान के साथ-साथ संबोधित करने का अतिरिक्त लाभ है। यहाँ हम इसके बजाय क्या करते हैं:

@implementation NSView (MyViewAdditions)

static void MySetFrame(id self, SEL _cmd, NSRect frame);
static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame);

static void MySetFrame(id self, SEL _cmd, NSRect frame) {
    // do custom work
    SetFrameIMP(self, _cmd, frame);
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP];
}

@end

हालांकि यह ऑब्जेक्टिव-सी की तरह थोड़ा कम दिखता है (क्योंकि यह फ़ंक्शन पॉइंटर्स का उपयोग कर रहा है), यह किसी भी नामकरण संघर्ष से बचता है। सिद्धांत रूप में, यह मानक स्विज़लिंग के समान सटीक काम कर रहा है। यह उन लोगों के लिए थोड़ा बदलाव हो सकता है जो झूलते हुए उपयोग कर रहे हैं क्योंकि इसे थोड़ी देर के लिए परिभाषित किया गया है, लेकिन अंत में, मुझे लगता है कि यह बेहतर है। इस प्रकार स्विज़लिंग पद्धति को परिभाषित किया गया है:

typedef IMP *IMPPointer;

BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) {
    IMP imp = NULL;
    Method method = class_getInstanceMethod(class, original);
    if (method) {
        const char *type = method_getTypeEncoding(method);
        imp = class_replaceMethod(class, original, replacement, type);
        if (!imp) {
            imp = method_getImplementation(method);
        }
    }
    if (imp && store) { *store = imp; }
    return (imp != NULL);
}

@implementation NSObject (FRRuntimeAdditions)
+ (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store {
    return class_swizzleMethodAndStore(self, original, replacement, store);
}
@end

विधियों का नाम बदलने से झूलने से विधि के तर्क बदल जाते हैं

यह मेरे दिमाग में एक बड़ी बात है। यही कारण है कि मानक विधि स्विज़लिंग नहीं किया जाना चाहिए। आप मूल विधि के कार्यान्वयन के लिए दिए गए तर्कों को बदल रहे हैं। यह वह जगह है जहाँ ऐसा होता है:

[self my_setFrame:frame];

यह लाइन क्या करती है:

objc_msgSend(self, @selector(my_setFrame:), frame);

जिसके क्रियान्वयन को देखने के लिए रनटाइम का उपयोग किया जाएगा my_setFrame:। एक बार कार्यान्वयन मिल जाने के बाद, यह उन्हीं तर्कों के साथ कार्यान्वयन को लागू करता है जो दिए गए थे। इसे लागू करने का मूल कार्यान्वयन है setFrame:, इसलिए यह आगे बढ़ता है और कॉल करता है, लेकिन _cmdतर्क ऐसा नहीं है setFrame:जैसा होना चाहिए। अभी है my_setFrame:। मूल कार्यान्वयन को एक ऐसे तर्क के साथ कहा जा रहा है जिसकी यह उम्मीद नहीं थी कि यह प्राप्त होगा। यह अच्छा नहीं है।

एक सरल उपाय है - ऊपर परिभाषित वैकल्पिक स्विज़लिंग तकनीक का उपयोग करें। तर्क अपरिवर्तित रहेंगे!

स्विज़ल्स का क्रम मायने रखता है

जिस क्रम में विधियों में परिवर्तन होता है। मान लिया गया है setFrame:कि केवल NSViewचीजों के इस क्रम की कल्पना करें:

[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];

क्या होता है जब विधि पर NSButtonज़ोर दिया जाता है? अच्छी तरह से सबसे अधिक झूलना सुनिश्चित करेगा कि यह setFrame:सभी विचारों के कार्यान्वयन की जगह नहीं ले रहा है , इसलिए यह उदाहरण विधि को ऊपर खींचेगा । यह मौजूदा कार्यान्वयन को कक्षा setFrame:में फिर से परिभाषित करने के लिए उपयोग करेगा NSButtonताकि कार्यान्वयन का आदान-प्रदान सभी विचारों को प्रभावित न करें। मौजूदा कार्यान्वयन वह है जिसे परिभाषित किया गया है NSView। एक ही बात तब होगी जब NSControl(फिर से NSViewकार्यान्वयन का उपयोग करते हुए ) झूलना होगा ।

जब आप setFrame:एक बटन पर कॉल करते हैं, तो यह आपके स्विज्ड विधि को कॉल करेगा, और फिर सीधे उस setFrame:विधि पर कूद जाएगा जिसे मूल रूप से परिभाषित किया गया है NSViewNSControlऔर NSViewswizzled कार्यान्वयन बुलाया नहीं किया जाएगा।

लेकिन क्या होगा अगर आदेश थे:

[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];

चूँकि दृश्य स्वीज़िंग पहले होता है, नियंत्रण स्विज़लिंग सही विधि को खींचने में सक्षम होगा । इसी तरह, चूंकि बटन स्वाइज़ करने से पहले कंट्रोल स्विज़लिंग होता था, इसलिए बटन कंट्रोल के स्विज़ल्ड कार्यान्वयन को खींच लेगा setFrame:। यह थोड़ा भ्रमित करने वाला है, लेकिन यह सही क्रम है। हम चीजों के इस क्रम को कैसे सुनिश्चित कर सकते हैं?

फिर, बस loadचीजों को स्वाइप करने के लिए उपयोग करें। यदि आप में झपकी लेते हैं loadऔर आप केवल लोड की जा रही कक्षा में परिवर्तन करते हैं, तो आप सुरक्षित रहेंगे। loadविधि गारंटी देता है कि सुपर वर्ग लोड विधि किसी भी उपवर्गों से पहले बुलाया जाएगा। हम सही सही आदेश मिलेगा!

समझने में मुश्किल (पुनरावर्ती दिखता है)

एक पारंपरिक रूप से परिभाषित जलपोत विधि को देखते हुए, मुझे लगता है कि वास्तव में यह बताना मुश्किल है कि क्या हो रहा है। लेकिन हमने जिस वैकल्पिक तरीके से ऊपर झूलते हुए देखा है, उसे देखना बहुत आसान है। यह पहले से ही हल हो गया है!

डिबग करना मुश्किल है

डिबगिंग के दौरान भ्रम की स्थिति में से एक में एक अजीब backtrace दिखाई दे रहा है जहां घुले हुए नामों को मिलाया जाता है और सब कुछ आपके सिर में उछल जाता है। फिर से, वैकल्पिक कार्यान्वयन इसे संबोधित करता है। आपको बैकट्रैक में स्पष्ट रूप से नामित कार्य दिखाई देंगे। फिर भी, झूलना डिबग करना मुश्किल हो सकता है क्योंकि यह याद रखना कठिन है कि झूलने का क्या प्रभाव पड़ रहा है। अपने कोड को अच्छी तरह से प्रलेखित करें (भले ही आपको लगता है कि आप केवल वही हैं जो इसे कभी देख पाएंगे)। अच्छी प्रथाओं का पालन करें, और आप ठीक हो जाएंगे। मल्टी-थ्रेडेड कोड की तुलना में डिबग करना कठिन नहीं है।

निष्कर्ष

यदि सही तरीके से उपयोग किया जाए तो विधि स्वाज़लिंग सुरक्षित है। एक सरल सुरक्षा उपाय जो आप अपना सकते हैं, वह केवल स्विज़ल में है load। प्रोग्रामिंग में कई चीजों की तरह, यह खतरनाक हो सकता है, लेकिन परिणामों को समझने से आप इसे ठीक से उपयोग कर पाएंगे।


1 ऊपर बताई गई स्विज़लिंग विधि का उपयोग करके, आप ट्रैम्पोलिन का उपयोग करने के लिए चीजों को सुरक्षित रख सकते हैं। आपको दो trampolines की आवश्यकता होगी। विधि के प्रारंभ में, आपको फ़ंक्शन पॉइंटर storeको एक फ़ंक्शन को असाइन करना होगा, जो उस पते तक घूमता है, जिसमें पता storeबदलने के लिए इंगित किया गया है। यह किसी भी दौड़ की स्थिति से बचना होगा, जिसमें storeफंक्शन पॉइंटर सेट करने में सक्षम होने से पहले स्विज़ल्ड पद्धति को बुलाया गया था । फिर आपको उस मामले में एक trampoline का उपयोग करने की आवश्यकता होगी जहां कार्यान्वयन पहले से ही वर्ग में परिभाषित नहीं किया गया है और जिसमें trampoline लुकअप है और सुपर क्लास विधि को ठीक से कॉल करें। विधि को परिभाषित करते हुए इसलिए यह गतिशील रूप से दिखता है कि सुपर कार्यान्वयन यह सुनिश्चित करेगा कि स्विज़लिंग कॉल का क्रम मायने नहीं रखता है।


24
आश्चर्यजनक जानकारीपूर्ण और तकनीकी रूप से ध्वनि उत्तर। चर्चा वास्तव में दिलचस्प है। यह लिखने के लिए समय निकालने के लिए धन्यवाद।
रिकार्डो सांचेज-साज़

क्या आप अनुभव कर सकते हैं कि ऐप स्टोर पर आपके अनुभव में बदलाव स्वीकार्य है या नहीं। मैं आपको stackoverflow.com/questions/8834294 पर भी निर्देशित कर रहा हूं ।
डिकी सिंह

3
स्विज़लिंग का उपयोग ऐप स्टोर पर किया जा सकता है। कई ऐप और फ्रेमवर्क (हमारे शामिल हैं)। ऊपर सब कुछ अभी भी पकड़ है, और आप निजी तरीकों (वास्तव में, आप तकनीकी रूप से नहीं कर सकते, लेकिन आप अस्वीकृति का जोखिम उठा सकते हैं और इस के खतरे एक अलग धागे के लिए हैं)।
wbyoung

अद्भुत जवाब। लेकिन कक्षा +swizzleMethodAndStore () में सीधे + स्विज़ल के बजाय: दुकान:? यह अतिरिक्त कार्य क्यों?
फ्रीजलैब

2
@Frizlab अच्छा सवाल! यह वास्तव में सिर्फ एक स्टाइल की चीज है। यदि आप ऐसे कोड का एक गुच्छा लिख ​​रहे हैं जो सीधे ऑब्जेक्टिव-सी रनटाइम एपीआई (सी में) के साथ काम कर रहा है, तो यह स्थिरता के लिए इसे सी शैली कहने में सक्षम होना अच्छा है। एकमात्र कारण मैं इसके अलावा सोच सकता हूं यदि आपने शुद्ध सी में कुछ लिखा है, तो यह अभी भी कॉल करने योग्य है। कोई कारण नहीं है कि आप इसे उद्देश्य-सी विधि में नहीं कर सकते, हालांकि।
18

12

पहले मैं सही तरीके से परिभाषित करूँगा कि मुझे क्या मतलब है

  • सभी कॉल को फिर से रूट करना जो मूल रूप से एक विधि (ए) को एक नई विधि (बी कहा जाता है) के लिए भेजा गया था।
  • हम मेथड बी
  • हम न ही अपनी विधि ए
  • मेथड B कुछ काम करता है फिर मेथड A कहता है।

विधि स्वाज़लिंग इस से अधिक सामान्य है, लेकिन यह वह मामला है जिसमें मुझे दिलचस्पी है।

खतरों:

  • मूल कक्षा में परिवर्तन । हम उस वर्ग के मालिक नहीं हैं जिसे हम निगल रहे हैं। यदि वर्ग बदलता है तो हमारा दलदल काम करना बंद कर सकता है।

  • बनाए रखने के लिए मुश्किल है । न केवल आपको लिखने और झूलने की विधि को बनाए रखने के लिए मिला है। आपको उस कोड को लिखना होगा और बनाए रखना होगा जो स्विज़ल को प्रीफ़ॉर्म करता है

  • डिबग करना मुश्किल है । एक स्विज़ल के प्रवाह का पालन करना कठिन है, कुछ लोगों को यह एहसास भी नहीं हो सकता है कि स्विज़ल पहले से विकृत हो गया है। यदि स्विज़ल से शुरू किए गए कीड़े हैं (शायद मूल वर्ग में परिवर्तन के लिए बकाया हैं) तो उन्हें हल करना मुश्किल होगा।

संक्षेप में, आपको एक न्यूनतम तक स्विज़लिंग रखना चाहिए और विचार करना चाहिए कि मूल वर्ग में परिवर्तन आपके स्विज़ल को कैसे प्रभावित कर सकते हैं। इसके अलावा, आपको स्पष्ट रूप से टिप्पणी और दस्तावेज़ करना चाहिए कि आप क्या कर रहे हैं (या बस इसे पूरी तरह से बचें)।


@ हर किसी ने मैंने आपके उत्तर एक अच्छे प्रारूप में जोड़ दिए हैं। इसे संपादित / जोड़ने के लिए स्वतंत्र महसूस करें। आपके सहयोग के लिए धन्यवाद।
रॉबर्ट

मैं आपके मनोविज्ञान का प्रशंसक हूं। "बड़ी तेज़ी के साथ बड़ी तेज़ी से ज़िम्मेदारी आती है।"
जैक्सनक्रा

7

यह अपने आप में डूबने वाला नहीं है जो वास्तव में खतरनाक है। जैसा कि आप कहते हैं, समस्या यह है कि इसका उपयोग अक्सर फ्रेमवर्क कक्षाओं के व्यवहार को संशोधित करने के लिए किया जाता है। यह मानकर चल रहा है कि आप कुछ जानते हैं कि वे निजी वर्ग कैसे काम करते हैं जो "खतरनाक" है। यहां तक ​​कि अगर आपके संशोधन आज भी काम करते हैं, तो हमेशा एक मौका होता है कि एप्पल भविष्य में कक्षा को बदल देगा और आपके संशोधन को तोड़ देगा। इसके अलावा, यदि कई अलग-अलग ऐप ऐसा करते हैं, तो यह यह बनाता है कि ऐप्पल के लिए बहुत सारे मौजूदा सॉफ़्टवेयर को तोड़ने के बिना फ्रेमवर्क को बदलना बहुत मुश्किल है।


मैं कहूंगा कि ऐसे देवता जो बोते हैं, उसे काट देना चाहिए - उन्होंने अपने कोड को किसी विशेष कार्यान्वयन के लिए कस दिया। इसलिए यह उनकी गलती है अगर उस कार्यान्वयन में एक सूक्ष्म तरीके से परिवर्तन होता है जो कि उनके कोड को नहीं तोड़ना चाहिए था यदि यह उनके स्पष्ट निर्णय के लिए उनके कोड को कसकर के रूप में उन्होंने नहीं किया था।
अनारंगियन

यकीन है, लेकिन कहते हैं कि iOS के अगले संस्करण के तहत एक बहुत लोकप्रिय ऐप टूट जाता है। यह कहना आसान है कि यह डेवलपर की गलती है और उन्हें बेहतर पता होना चाहिए, लेकिन यह उपयोगकर्ता की आंखों में एप्पल को खराब करता है। मुझे आपके स्वयं के तरीकों या यहां तक ​​कि कक्षाओं को स्वाहा करने में कोई हानि नहीं दिखती है यदि आप ऐसा करना चाहते हैं, तो अपनी बात से अलग यह कोड को कुछ भ्रामक बना सकता है। जब आप किसी और के द्वारा नियंत्रित किए जाने वाले कोड को स्वाइल करते हैं, तो यह थोड़ा अधिक जोखिम भरा होने लगता है - और यह ठीक उसी स्थिति में है, जब स्विज़लिंग ऐसा आकर्षक लगता है।
कालेब

Apple बेस कक्षाओं का एकमात्र प्रदाता नहीं है जिसे शिवलिंग के माध्यम से संशोधित किया जा सकता है। आपके उत्तर को सभी को शामिल करने के लिए संपादित किया जाना चाहिए।
एआर

@AR शायद, लेकिन सवाल iOS और iPhone को टैग किया गया है, इसलिए हमें इस संदर्भ में विचार करना चाहिए। यह देखते हुए कि आईओएस ऐप को आईओएस द्वारा प्रदान किए गए लोगों के अलावा किसी भी लाइब्रेरी और फ्रेमवर्क को जोड़ना होगा, ऐप्पल वास्तव में एकमात्र इकाई है जो ऐप डेवलपर्स से कुछ भागीदारी के बिना फ्रेमवर्क कक्षाओं के कार्यान्वयन को बदल सकता है। लेकिन मैं इस बात से सहमत हूं कि इसी तरह के मुद्दे अन्य प्लेटफार्मों को प्रभावित करते हैं, और मैं कहूंगा कि सलाह को स्वाइलिंग के अलावा भी सामान्यीकृत किया जा सकता है। सामान्य रूप में, सलाह यह है: अपने हाथ अपने पास रखें। अन्य लोगों को बनाए रखने वाले घटकों को संशोधित करने से बचें।
कालेब

विधि स्वाज़लिंग उस खतरनाक हो सकती है। लेकिन जैसा कि चौखटे बाहर आते हैं वे पिछले वाले को पूरी तरह से छोड़ नहीं देते हैं। आपको अभी भी अपने ऐप की अपेक्षा बेस फ्रेमवर्क को अपडेट करना है। और वह अपडेट आपके ऐप को तोड़ देगा। जब आईओएस को अपडेट किया जाता है तो यह उतनी बड़ी समस्या नहीं है। मेरा उपयोग पैटर्न डिफ़ॉल्ट reuseIdentifier को ओवरराइड करने के लिए था। चूँकि मेरे पास _reuseIdentifier वैरिएबल की कोई पहुँच नहीं थी और इसे तब तक प्रतिस्थापित नहीं करना चाहता था जब तक कि इसे प्रदान नहीं किया गया था जब तक कि मेरा एकमात्र समाधान हर एक को उपवर्गित नहीं करना था और पुन: उपयोग करने वाले पहचानकर्ता या स्वाइल प्रदान करना और शून्य होने पर ओवरराइड करना था। कार्यान्वयन प्रकार कुंजी है ...
आलसी कोडर

5

सावधानीपूर्वक और समझदारी से उपयोग किया गया, यह सुरुचिपूर्ण कोड को जन्म दे सकता है, लेकिन आमतौर पर, यह सिर्फ भ्रमित कोड की ओर जाता है।

मैं कहता हूं कि इस पर प्रतिबंध लगाया जाना चाहिए, जब तक कि आपको यह पता न चले कि यह किसी विशेष डिजाइन कार्य के लिए एक बहुत ही सुंदर अवसर प्रस्तुत करता है, लेकिन आपको यह स्पष्ट रूप से जानना होगा कि यह स्थिति पर क्यों लागू होता है, और विकल्प स्थिति के लिए सुरुचिपूर्ण ढंग से काम क्यों नहीं करते हैं। ।

उदाहरण के लिए, विधि स्विज़लिंग का एक अच्छा अनुप्रयोग isa swizzling है, जो कि ObjC कुंजी मूल्य अवलोकन को कैसे लागू करता है।

एक बुरा उदाहरण हो सकता है कि आपकी कक्षाओं को बढ़ाने के साधन के रूप में विधि स्वाइलिंग पर निर्भर हो, जो कि बहुत अधिक युग्मन की ओर जाता है।


1
केवीओ के उल्लेख के लिए -1 - विधि स्विज़लिंग के संदर्भ में । isa swizzling सिर्फ कुछ और है।
निकोलाई रुहे

@NikolaiRuhe: कृपया संदर्भ प्रदान करने के लिए स्वतंत्र महसूस करें ताकि मुझे प्रबुद्ध किया जा सके।
अराफंगियन

यहां केवीओ के कार्यान्वयन विवरण का संदर्भ दिया गया है । कोकोआडेव पर विधि स्वाज़लिंग का वर्णन किया गया है।
निकोलाई रुहे

5

हालाँकि मैंने इस तकनीक का उपयोग किया है, फिर भी मैं यह बताना चाहूंगा:

  • यह आपके कोड को बाधित करता है क्योंकि यह अन-डॉक्यूमेंटेड हो सकता है, हालांकि वांछित, साइड इफेक्ट्स। जब कोई कोड पढ़ता है तो वह / वह साइड इफेक्ट व्यवहार से अनजान हो सकता है जो तब तक आवश्यक होता है जब तक कि वह कोड आधार खोज करने के लिए याद नहीं करता है कि क्या यह झूला हुआ है। मुझे यकीन नहीं है कि इस समस्या को कैसे कम किया जाए क्योंकि यह हर उस स्थान पर दस्तावेज़ करना हमेशा संभव नहीं होता है जहाँ कोड साइड इफ़ेक्ट स्वाज़ल व्यवहार पर निर्भर है।
  • यह आपके कोड को कम पुन: उपयोग योग्य बना सकता है क्योंकि कोई ऐसा व्यक्ति जो कोड का एक खंड पाता है, जो कि बर्खास्त किए गए व्यवहार पर निर्भर करता है कि वे कहीं और उपयोग करना चाहते हैं, बस इसे काटे गए तरीके को खोजने और कॉपी किए बिना किसी अन्य कोड आधार में काट और पेस्ट नहीं कर सकते।

4

मुझे लगता है कि सबसे बड़ा खतरा कई अवांछित दुष्प्रभाव पैदा करना है, पूरी तरह से दुर्घटना से। ये दुष्प्रभाव खुद को 'बग' के रूप में पेश कर सकते हैं जो समाधान खोजने के लिए गलत रास्ते पर ले जाते हैं। मेरे अनुभव में, खतरा अवैध, भ्रामक और निराशाजनक कोड है। जब कोई C ++ में फंक्शन पॉइंटर्स को ओवरएज करता है, तो उसकी तरह।


ठीक है, इसलिए समस्या यह है कि यह डिबग करना कठिन है। समस्याएँ इसलिए होती हैं क्योंकि समीक्षक यह नहीं समझते / भूल जाते हैं कि कोड को स्वाइप कर दिया गया है और डिबगिंग करते समय गलत स्थान पर दिख रहे हैं।
रॉबर्ट

3
हाँ बहुत ज्यादा। इसके अलावा, जब overused आप एक अंतहीन श्रृंखला या swizzles के वेब में प्राप्त कर सकते हैं। कल्पना कीजिए कि जब आप भविष्य में किसी बिंदु पर उनमें से सिर्फ एक को बदलते हैं तो क्या हो सकता है? मैं अनुभव को चाय की स्टैकिंग या 'कोड जेंगा' खेलने के लिए पसंद करता हूं
AR

4

आप विषम दिखने वाले कोड की तरह समाप्त हो सकते हैं

- (void)addSubview:(UIView *)view atIndex:(NSInteger)index {
    //this looks like an infinite loop but we're swizzling so default will get called
    [self addSubview:view atIndex:index];

कुछ यूआई जादू से संबंधित वास्तविक उत्पादन कोड से।


3

यूनिट टेस्टिंग में मेथड स्विज़लिंग बहुत मददगार हो सकता है।

यह आपको एक नकली वस्तु लिखने की अनुमति देता है और वास्तविक वस्तु के बजाय उस नकली वस्तु का उपयोग किया जाता है। आपका कोड साफ रहने के लिए और आपके यूनिट परीक्षण में अनुमानित व्यवहार है। मान लें कि आप कुछ कोड का परीक्षण करना चाहते हैं जो CLLocationManager का उपयोग करता है। आपकी इकाई परीक्षण startUpdatingLocation को स्वाइल कर सकती है ताकि यह आपके प्रतिनिधि को स्थानों का पूर्व निर्धारित सेट खिला दे और आपके कोड को बदलना न पड़े।


isa-swizzling एक बेहतर विकल्प होगा।
vikingosegundo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.