उद्देश्य-सी में मेटाक्लासेस

यह लेख ऑब्जेक्टिव-सी में एक मेटा-क्लास क्या है, का अनुवाद है।

अनुवाद कॉपीराइट है। लघु परिवर्धन मुख्य रूप से Apple के प्रलेखन की चिंता करते हैं और केवल सम्मानित पाठकों की सुविधा के लिए जोड़े जाते हैं। किसी लेख के अनुवाद की नकल करते समय, मूल अनुवाद के लिंक की आवश्यकता होती है। संयुक्त कार्य का सम्मान करते हैं।


छोटा सा परिचय

आइए ऑब्जेक्ट-सी भाषा की ऐसी अवधारणा को मेटाक्लस के रूप में मानने का प्रयास करें।
उद्देश्य-सी सीखने का फैसला करने वाले किसी भी शुरुआत की तरह, मैं एक विस्तार के बारे में उत्सुक हो गया।
यदि एक ही समय में एक क्लास एक ऑब्जेक्ट है और हम इसे संदेश भेज सकते हैं जो क्लास विधि को कॉल करते हैं (रिटर्न प्रकार से पहले एक "+" है), तो ऐसी ऑब्जेक्ट क्लास क्या है?

सबसे पहले, याद रखें कि क्लास विधि किस तरह से इंस्टेंस विधि से भिन्न होती है।

@interface MyClass : NSObject + (void)aClassMethod; //  - (void)anInstanceMethod; //  @end ................................................. [MyClass aClassMethod]; //   + (void)aClassMethod; MyClass *object = [[MyClass alloc] init]; //   MyClass [object anInstanceMethod]; //   - (void)anInstanceMethod; 


जैसा कि आप देख सकते हैं, वर्ग विधि को कॉल करने के लिए आपको कक्षा का एक अलग उदाहरण बनाने की आवश्यकता नहीं है। संदेश भेजते समय, केवल कक्षा का नाम निर्दिष्ट करें।

रन-टाइम पर मैन्युअल रूप से क्लास बनाना

तो, ऑब्जेक्टिव-सी में प्रत्येक वर्ग की अपनी संगत मेटाक्लास है। आइए, रन टाइम में मेटाक्लस पर नजर डालते हैं।
मैन्युअल रूप से रनटाइम में एक क्लास बनाएं।
निम्न कोड NSError का RuntimeErrorSubclass उपवर्ग उप-वर्ग करता है और इसमें रिपोर्ट विधि जोड़ता है

 Class newClass = objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0); class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:"); objc_registerClassPair(newClass); 


Class_addMethod फ़ंक्शन का उपयोग करके जोड़ा गया है , रिपोर्ट विधि ReportFunction फ़ंक्शन का उपयोग करती है ( इंप्रेशन एक फ़ंक्शन के लिए एक संकेतक है जो नई विधि को लागू करता है। फ़ंक्शन को कम से कम दो मापदंडों को स्वीकार करना चाहिए - स्वयं और _cmd ), जिसकी निम्न परिभाषा है:

 void ReportFunction(id self, SEL _cmd) { NSLog(@"This object is %p.", self); NSLog(@"Class is %@, and super is %@.", [self class], [self superclass]); Class currentClass = [self class]; for (int i = 1; i < 5; i++) { NSLog(@"Following the isa pointer %d times gives %p", i, currentClass); currentClass = object_getClass(currentClass); } NSLog(@"NSObject's class is %p", [NSObject class]); NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class])); } 


बाह्य रूप से, सब कुछ काफी सरल दिखता है। केवल तीन चरणों में, हमने एक वर्ग बनाया।
1. objc_allocateClassPair का उपयोग करके एक वर्ग बनाएं
2. class_addMethod का उपयोग करके इसे एक विधि में जोड़ा गया (यदि वांछित है, तो आप class_addIvar का उपयोग करके चर जोड़ सकते हैं)
3. objc_registerClassPair का उपयोग करके वर्ग पंजीकृत करें

उसी समय, सवाल उठता है: "क्लास पेयर" क्या है? बेशक, यदि आप Apple दस्तावेज़ीकरण को देखते हैं और objc_allocateClassPair फ़ंक्शन के विवरण को देखते हैं, तो आप देख सकते हैं कि यह न केवल एक वर्ग बनाता है, बल्कि हमारे रहस्यमय मेटाक्लस भी बनाता है। यहाँ कुछ कक्षाएं हैं।
लेकिन मेटाक्लास की अवधारणा को समझने के लिए, आपको कुछ मूल बातों से खुद को परिचित करना होगा।

जब एक डेटा संरचना को एक वस्तु के रूप में माना जा सकता है

प्रत्येक वस्तु में एक वर्ग होता है। यह ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग की एक बुनियादी अवधारणा है, लेकिन ऑब्जेक्टिव-सी में यह डेटा संरचना का एक अनिवार्य हिस्सा भी है। किसी भी डेटा संरचना में एक कक्षा के लिए एक संकेतक है जिसे एक वस्तु के रूप में माना जा सकता है।

Objective-C में, एक ऑब्जेक्ट क्लास को isa पॉइंटर का उपयोग करके परिभाषित किया जाता है।

सामान्य तौर पर, Objective-C में एक मूल वस्तु परिभाषा इस तरह दिख सकती है:

 typedef struct objc_object { Class isa; } *id; 


इसका मतलब यह है कि किसी भी डेटा संरचना जो एक कक्षा के लिए एक सूचक के साथ शुरू होती है उसे एक वस्तु के रूप में माना जा सकता है।

ऑब्जेक्टिव-सी में वस्तुओं की सबसे महत्वपूर्ण विशेषता वस्तुओं को संदेश भेजने की क्षमता है।

 [@"stringValue" writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL]; 


यह काम करता है क्योंकि जब आप किसी ऑब्जेक्ट-सी ऑब्जेक्ट (जैसे NSCFString ऊपर) को संदेश भेजते हैं, रनटाइम isa वर्ग के लिए एक पॉइंटर का अनुसरण करता है, जो ऑब्जेक्ट के वर्ग (NSCFString वर्ग, हमारे मामले में) की ओर जाता है। कक्षा में उन विधियों की एक सूची शामिल होती है जो विरासत में मिली विधियों को देखने के लिए इस वर्ग की सभी वस्तुओं और एक सुपरक्लास (या सुपरक्लास) के लिए एक संकेतक पर लागू की जा सकती हैं। रनटाइम संदेश चयनकर्ता (उपरोक्त मामले में, writeToFile: atomically: एन्कोडिंग: NSString पर त्रुटि ) से मेल खाने वाली विधि खोजने के लिए वर्ग और सुपरक्लास विधियों की सूची के माध्यम से दिखता है। अगला, रनटाइम इस विधि के लिए फ़ंक्शन ( IMP ) को कॉल करता है।

महत्वपूर्ण बिंदु यह है कि कक्षा निर्धारित करती है कि वस्तु को कौन से संदेश भेजे जा सकते हैं।

मेटाक्लास क्या है?

जैसा कि आप पहले से ही जानते हैं, ऑब्जेक्टिव-सी में क्लास भी ऑब्जेक्ट हैं। इसका मतलब है कि आप कक्षा को संदेश भेज सकते हैं।

 NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding]; 


इस स्थिति में, DefaultStringEncoding संदेश NSString वर्ग को भेजा जाता है।

यह काम करता है क्योंकि Objective-C में हर वर्ग एक ऑब्जेक्ट भी है। इसका मतलब यह है कि वर्ग की संरचना भी सूचक के साथ वर्ग आइसा से शुरू होती है, इसलिए इसकी संरचना ऊपर चर्चा की गई वस्तु की संरचना के समान है, और संरचना का अगला क्षेत्र सुपरक्लास (या बेस कक्षाओं के लिए शून्य) का सूचक होना चाहिए।

हालाँकि, कक्षाओं की संरचना रनटाइम वातावरण के संस्करण के आधार पर भिन्न हो सकती है, वे सभी पॉइंटर फ़ील्ड से आइसा क्लास और पॉइंटर से सुपरक्लास तक शुरू करते हैं।

 typedef struct objc_class *Class; struct objc_class { Class isa; Class super_class; /*      ... */ }; 


हालाँकि, क्लास विधि को कॉल करने के लिए, क्लास isa को पॉइंटर को क्लास संरचना की ओर इशारा करना चाहिए और इस क्लास संरचना में उन विधियों की सूची होनी चाहिए, जिन्हें क्लास कॉल कर सकती है।

यह हमें मेटाक्लस की परिभाषा की ओर ले जाता है: एक मेटाक्लास एक क्लास ऑब्जेक्ट के लिए क्लास है।

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

मेटाक्लास की आवश्यकता होती है, क्योंकि वे वर्ग विधियों को संग्रहीत करते हैं। प्रत्येक कक्षा के लिए एक विशिष्ट मेटाक्लस होना चाहिए, क्योंकि प्रत्येक कक्षा में क्लास विधियों की एक संभावित अनूठी सूची होती है।

मेटाक्लास के लिए कक्षा क्या है?

पहले की चर्चा की गई कक्षाओं की तरह मेटाक्लस भी एक वस्तु है। इसका मतलब है कि आप मेटाक्लास विधियों को भी कॉल कर सकते हैं। सामान्य तौर पर, इसका मतलब है कि मेटाक्लास में एक वर्ग भी होना चाहिए।

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

इस नियम का पालन करते हुए कि कक्षा के आधार मेटाक्लास का अपनी कक्षा के रूप में उपयोग करने वाले सभी मेटाकालेज़ के लिए, कोई भी बेस मेटाकालेज़ उनकी अपनी कक्षा होगी (उनका आइसा पॉइंटर सीधे उनके लिए इंगित करेगा)। इसका मतलब यह है कि NSObject मेटाकाॅल का आइसा पॉइंटर अपने आप को इंगित करता है।

कक्षाओं और मेटाक्लेसेस का पदानुक्रम।

सुपरक्लास पॉइंटर का उपयोग करने वाले एक क्लास की तरह सुपरक्लास पॉइंटर, मेटाक्लास का अपना सुपर_क्लास पॉइंटर होता है जो क्लास के सुपरक्लास मेटाक्लास में होता है।

बेस मेटोक्लास के सुपरक्लास का एक संकेतक खुद को इंगित करता है।

इस पदानुक्रम का नतीजा यह है कि पदानुक्रम में सभी उदाहरण, वर्ग और मेटाक्लासेस बेस क्लास पदानुक्रम से विरासत में मिले हैं।

NSObject पदानुक्रम में सभी उदाहरणों, कक्षाओं, और मेटाक्लासेस के लिए, इसका मतलब है कि NSObject उदाहरण के सभी तरीके उन पर भी लागू होते हैं।

हालांकि यह सब एक परीक्षण के रूप में बहुत अच्छा लग रहा है, ग्रेग पार्कर ने उदाहरणों, वर्गों और मेटाक्लस के पदानुक्रम को दर्शाते हुए एक महान आरेख की पेशकश की।

छवि

प्रायोगिक पुष्टि।

उपरोक्त पुष्टि करने के लिए, आइए हम ReportFunction फ़ंक्शन के आउटपुट को देखें , जिसे हमने शुरुआत में लिखा था।
हमारा लक्ष्य इसा संकेत का पालन करना है और जो कुछ भी पाया जाएगा उसे लिखना होगा।

ReportFunction का उपयोग करने के लिए, हमें एक गतिशील रूप से बनाई गई कक्षा को तुरंत रिपोर्ट करने और रिपोर्ट विधि को कॉल करने की आवश्यकता है

 id instanceOfNewClass = [[newClass alloc] initWithDomain:@"someDomain" code:0 userInfo:nil]; [instanceOfNewClass performSelector:@selector(report)]; [instanceOfNewClass release]; 


चूंकि हमारे पास रिपोर्ट पद्धति के लिए घोषणा नहीं है, इसलिए हम इसे प्रदर्शनकर्ता फ़ंक्शन के साथ कहते हैं, इसलिए संकलक हमें चेतावनी नहीं देता है।

इसके बाद, ReportFunction isa पॉइंटर्स को पास करता है और हमें बताता है कि किस ऑब्जेक्ट को एक क्लास के रूप में उपयोग किया जाता है, जो कि मेटाक्लास और मेटाक्लास क्लास के रूप में एक है।

ऑब्जेक्ट क्लास प्राप्त करना: ReportFunction फ़ंक्शन, पॉइंटर्स को isa क्लास में ले जाने के लिए object_getClass फ़ंक्शन का उपयोग करता है, क्योंकि isa पॉइंटर क्लास का एक संरक्षित सदस्य है (आप हमारी श्रृंखला में अन्य ऑब्जेक्ट्स के isa पॉइंटर को सीधे एक्सेस नहीं कर सकते हैं)।
ReportFunction भी क्लास विधि द्वारा क्लास विधि के कॉल का उपयोग नहीं करता है, क्योंकि क्लास विधि के लिए कॉल मेटाक्लास वापस नहीं करता है, लेकिन इसके बजाय क्लास को फिर से लौटाता है (उदाहरण के लिए, [NSString वर्ग] मेटासेलिंग के बजाय NSString क्लास को फिर से लौटा देगा)।
object_getClass उस कक्षा का ऑब्जेक्ट लौटाता है जिसका उदाहरण तर्क के रूप में पास की गई वस्तु है।

 Class object_getClass(id object) 


हमारे कार्यक्रम का समापन:
 This object is 0x10010c810. Class is RuntimeErrorSubclass, and super is NSError. Following the isa pointer 1 times gives 0x10010c600 Following the isa pointer 2 times gives 0x10010c630 Following the isa pointer 3 times gives 0x7fff71038480 Following the isa pointer 4 times gives 0x7fff71038480 NSObject's class is 0x7fff710384a8 NSObject's meta class is 0x7fff71038480 


प्राप्त पतों को देखते हुए:

ऑब्जेक्ट: 0x10010c810।
क्लास: 0x10010c600
मेटाक्लस: 0x10010c630।
मेटाक्लास क्लास (मेटाक्लास NSObject) 0x7fff71038480
NSObject मेटाक्लास क्लास NSObject मेटाक्लास स्वयं ( isa points to only) है।

पते के मान वास्तव में महत्वपूर्ण नहीं हैं, सिवाय इसके कि वे पहले से चर्चा किए गए रूपक NSObject से मेटाक्लर्स के पदानुक्रम को दिखाते हैं।

निष्कर्ष

मेटाक्लास एक क्लास ऑब्जेक्ट का एक वर्ग है। प्रत्येक वर्ग की अपनी अनूठी मेटाक्लास होती है (चूंकि प्रत्येक कक्षा की अपनी अनूठी सूची होती है)।

मेटाक्लास हमेशा सुनिश्चित करता है कि क्लास ऑब्जेक्ट में बेस क्लास के सभी आवश्यक चर और तरीके, साथ ही साथ क्लास के सभी तरीके हैं। NSObject से प्राप्त होने वाली कक्षाओं के लिए, इसका मतलब है कि NSObject वर्ग के सभी उदाहरण तरीके और NSObject के प्रोटोकॉल तरीकों को व्युत्पन्न वर्गों और मेटाक्लासेस की सभी वस्तुओं के लिए परिभाषित किया गया है।

सभी मेटाक्लस NSObject वर्ग के बेस मेटाक्लास को अपनी कक्षा के रूप में उपयोग करते हैं।

Source: https://habr.com/ru/post/In207786/


All Articles