उद्देश्य-सी: आईडी और शून्य के बीच का अंतर *


जवाबों:


240

void * का अर्थ है "अनकैप्ड / अज्ञात सामग्री के साथ कुछ रैंडम चंक ओ 'मेमोरी का संदर्भ"

id "अज्ञात वर्ग के कुछ यादृच्छिक उद्देश्य-सी वस्तु का संदर्भ"

अतिरिक्त सिमेंटिक अंतर हैं:

  • जीसी ओनली या जीसी सपोर्टेड मोड्स के तहत, कंपाइलर टाइप के रेफरेंस के लिए बैरियर लिखेगा id, लेकिन टाइप के लिए नहीं void *। संरचनाओं की घोषणा करते समय, यह एक महत्वपूर्ण अंतर हो सकता है। void *_superPrivateDoNotTouch;यदि _superPrivateDoNotTouchवास्तव में एक वस्तु है, तो iVars की घोषणा करने से वस्तुओं का समय से पहले रिसाव होगा । ऐसा मत करो।

  • एक void *प्रकार के संदर्भ पर एक विधि को लागू करने का प्रयास एक कंपाइलर चेतावनी को रोक देगा।

  • एक idप्रकार पर एक विधि को लागू करने का प्रयास केवल तभी चेतावनी देगा जब बुलाया जा रहा विधि @interfaceसंकलक द्वारा देखी गई किसी भी घोषणा में घोषित नहीं की गई है।

इस प्रकार, किसी को एक वस्तु के रूप में संदर्भित नहीं करना चाहिए void *। इसी प्रकार, idकिसी वस्तु को संदर्भित करने के लिए टाइप किए गए चर का उपयोग करने से बचना चाहिए । सबसे विशिष्ट वर्ग टाइप किए गए संदर्भ का उपयोग करें। इससे NSObject *भी बेहतर है idक्योंकि संकलक, कम से कम, उस संदर्भ के खिलाफ विधि इनवोकेशन का बेहतर सत्यापन प्रदान कर सकता है।

इसका एक सामान्य और मान्य उपयोग void *अपारदर्शी डेटा संदर्भ के रूप में है जो किसी अन्य एपीआई के माध्यम से पारित किया जाता है।

की sortedArrayUsingFunction: context:विधि पर विचार करें NSArray:

- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;

छँटाई समारोह के रूप में घोषित किया जाएगा:

NSInteger mySortFunc(id left, id right, void *context) { ...; }

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

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

नाजुक और त्रुटि प्रवण, लेकिन एकमात्र तरीका।

ब्लॉक इसे हल करते हैं - ब्लॉक सी के लिए क्लोजर हैं। वे क्लैंग में उपलब्ध हैं - http://llvm.org/ और स्नो लेपर्ड ( http://developer.apple.com/library/ios/documentation/Performance) में व्याप्त हैं /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf )।


इसके अतिरिक्त, मुझे पूरा यकीन है कि ए idको जवाब देने के लिए मान लिया गया है -retainऔर -releaseजबकि void*कैली के लिए यह पूरी तरह से अपारदर्शी है। आप एक मनमाने ढंग से पॉइंटर को पास नहीं कर सकते -performSelector:withObject:afterDelay:(यह ऑब्जेक्ट को बनाए रखता है), और आप यह नहीं मान सकते हैं कि +[UIView beginAnimations:context:]संदर्भ बरकरार रहेगा (एनीमेशन प्रतिनिधि को संदर्भ का स्वामित्व बनाए रखना चाहिए; UIKit एनीमेशन प्रतिनिधि को बरकरार रखता है)।
टीसी

3
इस बात का कोई अनुमान नहीं लगाया जा सकता है कि इसका idजवाब क्या होगा। एक idआसानी से उस वर्ग की एक आवृत्ति का उल्लेख कर सकता है जो अंतर्निहित नहीं है NSObject। व्यावहारिक रूप से, हालांकि, आपका कथन वास्तविक विश्व व्यवहार से सबसे अच्छा मेल खाता है; आप <NSObject>फाउंडेशन एपीआई के साथ गैर- कार्यान्वयन कक्षाएं नहीं मिला सकते हैं और बहुत दूर हो सकते हैं, यह निश्चित रूप से निश्चित है!
bbum

2
अब idऔर Classप्रकारों को एआरसी के तहत अनुरक्षण योग्य वस्तु सूचक के रूप में माना जा रहा है । तो यह धारणा कम से कम एआरसी के तहत सही है।
eonil

"समय से पहले कटाई" क्या है?
ब्रैड थॉमस

1
@BradThomas जब कोई कचरा संग्रहकर्ता कार्यक्रम से पहले मेमोरी जमा करता है।
bbum

21

id एक ऑब्जेक्टिव C ऑब्जेक्ट का पॉइंटर है, जहाँ void * किसी भी चीज़ का पॉइंटर है।

आईडी अज्ञात mthods को कॉल करने से संबंधित चेतावनियों को भी बंद कर देती है, इसलिए उदाहरण के लिए:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

अज्ञात तरीकों के बारे में सामान्य चेतावनी नहीं देंगे। यह निश्चित रूप से, रन समय में एक अपवाद को बढ़ाएगा जब तक कि ओबीज शून्य नहीं होता है या वास्तव में उस पद्धति को लागू नहीं करता है।

अक्सर आपको उपयोग करना चाहिए NSObject*या id<NSObject>वरीयता में होना चाहिए id, जो कम से कम इस बात की पुष्टि करता है कि लौटाई गई वस्तु एक कोको ऑब्जेक्ट है, इसलिए आप सुरक्षित रूप से उस पर बनाए रखने / जारी करने / ऑटोरेलिज जैसे तरीकों का उपयोग कर सकते हैं।


2
विधि इनवोकेशन के लिए, टाइप (आईडी) का एक लक्ष्य एक चेतावनी उत्पन्न करेगा यदि लक्षित विधि कहीं भी घोषित नहीं की गई है। इस प्रकार, आपके उदाहरण में, doSomethingWeirdYouveNeverHeardOf को चेतावनी न होने के लिए कहीं न कहीं घोषित किया गया होगा।
bbum

आप सही समझ रहे हैं, एक बेहतर उदाहरण भंडारण की तरह कुछ होगा।
पीटर एन लुईस

@PeterNLewis के Often you should use NSObject*बजाय मैं इससे असहमत हूं id। निर्दिष्ट करके NSObject*आप वास्तव में स्पष्ट रूप से कह रहे हैं कि ऑब्जेक्ट एक NSObject है। ऑब्जेक्ट के लिए किसी भी विधि को कॉल करने पर एक चेतावनी होगी, लेकिन जब तक कि ऑब्जेक्ट वास्तव में विधि कॉल का जवाब नहीं देता तब तक कोई रनटाइम अपवाद नहीं होगा। चेतावनी स्पष्ट रूप से कष्टप्रद है इसलिए idबेहतर है। मोटे तौर पर आप उदाहरण के लिए यह कहकर और अधिक विशिष्ट हो सकते हैं id<MKAnnotation>, जो इस मामले में है कि जो भी वस्तु का मतलब है, वह एमकेएनओनेटेशन प्रोटोकॉल के अनुरूप होना चाहिए।
pnizzle

1
यदि आप आईडी <MKAnnotation> का उपयोग करने जा रहे हैं, तो आप बस NSObject <MKAnnotation> * का उपयोग कर सकते हैं। जो तब आपको MKAnnotation में और NSObject में किसी भी तरीके का उपयोग करने की अनुमति देता है (यानी, सामान्य NSObject रूट क्लास पदानुक्रम में सभी ऑब्जेक्ट), और किसी भी चीज़ के लिए एक चेतावनी प्राप्त करें, जो बिना किसी चेतावनी के बहुत बेहतर है और एक क्रम दुर्घटना।
पीटर एन लुईस

8

यदि किसी विधि का रिटर्न प्रकार है idतो आप किसी भी ऑब्जेक्ट-सी ऑब्जेक्ट को वापस कर सकते हैं।

void इसका मतलब है, विधि कुछ भी नहीं लौटाएगी।

void *सिर्फ एक सूचक है। आप पॉइंटर पॉइंट के पते पर कंटेंट को एडिट नहीं कर पाएंगे।


2
जैसा कि यह एक विधि के रिटर्न मूल्य पर लागू होता है, ज्यादातर सही है। जैसा कि यह घोषित चर या तर्कों पर लागू होता है, काफी नहीं। और आप हमेशा (विशिष्ट) टाइप कर सकते हैं यदि आप सामग्री पढ़ना / लिखना चाहते हैं - तो ऐसा नहीं है कि ऐसा करना एक अच्छा विचार है।
bbum

8

idऑब्जेक्टिव-सी ऑब्जेक्ट का पॉइंटर है। void *किसी भी चीज का सूचक है । आप void *इसके बजाय उपयोग कर सकते हैं id, लेकिन यह अनुशंसित नहीं है क्योंकि आपको कभी भी किसी चीज़ के लिए संकलक चेतावनी नहीं मिलेगी।

आप stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject और unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs- देखना चाह सकते हैं -id.html


1
काफी नहीं। (शून्य *) टाइप किए गए चर बिल्कुल भी तरीके के इनवोकेशन का लक्ष्य नहीं हो सकते हैं। यह संकलक से "चेतावनी: अवैध रिसीवर प्रकार 'शून्य *" का परिणाम है।
बीबीएम

@bbum: void *टाइप किए गए चर सबसे निश्चित रूप से विधि इनवोकेशन का लक्ष्य हो सकते हैं- यह एक चेतावनी है, त्रुटि नहीं। इतना ही नहीं, आप यह कर सकते हैं: int i = (int)@"Hello, string!";और साथ पालन करें printf("Sending to an int: '%s'\n", [i UTF8String]);:। यह एक चेतावनी है, एक त्रुटि नहीं (और बिल्कुल अनुशंसित नहीं, न ही पोर्टेबल)। लेकिन आप इन चीजों को क्यों कर सकते हैं इसका कारण सभी बुनियादी सी है
जॉन्ह

1
माफ़ करना। तुम सही हो; यह एक चेतावनी है, त्रुटि नहीं। मैं हमेशा चेतावनी को हमेशा और हर जगह त्रुटियों के रूप में मानता हूं।
BBum

4
/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

उपरोक्त कोड objc.h से है, इसलिए ऐसा लग रहा है कि id objc_object संरचना का एक उदाहरण है और isa पॉइंटर किसी भी ऑब्जेक्टिव C क्लास ऑब्जेक्ट के साथ बाँध सकता है, जबकि void * केवल एक अनइंस्टॉल पॉइंटर है।


2

मेरी समझ यह है कि आईडी एक संकेतक को एक वस्तु का प्रतिनिधित्व करता है जबकि शून्य * वास्तव में कुछ भी इंगित कर सकता है, जब तक कि आप इसे उस प्रकार के लिए डाल दें जिसे आप इसका उपयोग करना चाहते हैं


यदि आप id सहित कुछ ऑब्जेक्ट प्रकार से (void *) कास्टिंग कर रहे हैं, तो आप बहुत गलत कर रहे हैं। ऐसा करने के लिए कारण हैं, लेकिन वे कम हैं, बहुत दूर हैं, और लगभग हमेशा एक डिजाइन दोष का संकेत देते हैं।
bbum

1
उद्धरण "ऐसा करने के लिए कारण हैं, लेकिन वे कुछ हैं," सच है कि के बीच। यह स्थिति पर निर्भर करता है। हालाँकि मैं कुछ संदर्भ के साथ "आप इसे गलत तरीके से करने की संभावना रखते हैं" जैसा एक कंबल बयान नहीं करेंगे।
हफीज

मैं एक कंबल बयान करूँगा; बीच में शून्य * के साथ गलत प्रकार के कास्टिंग के कारण बहुत सारे शापित कीड़े को नीचे शिकार करना और ठीक करना था। एक अपवाद कॉलबैक आधारित एपीआई है जो एक शून्य * संदर्भ तर्क लेता है जिसका अनुबंध बताता है कि कॉलबैक स्थापित करने और कॉलबैक प्राप्त करने के बीच संदर्भ अछूता रहेगा।
bbum

0

पहले से ही कहा गया है के अलावा, संग्रह से संबंधित वस्तुओं और संकेत के बीच अंतर है। उदाहरण के लिए, यदि आप NSArray में कुछ डालना चाहते हैं, तो आपको एक ऑब्जेक्ट (प्रकार "आईडी") की आवश्यकता होती है, और आप वहां एक कच्चे डेटा पॉइंटर का उपयोग नहीं कर सकते हैं (प्रकार "शून्य *")। आप इसे संग्रह के अंदर उपयोग [NSValue valueWithPointer:rawData]करने के void *rawDdataलिए "आईडी" प्रकार में परिवर्तित करने के लिए उपयोग कर सकते हैं। सामान्य तौर पर "आईडी" अधिक लचीली होती है और इसमें संलग्न वस्तुओं से संबंधित शब्दार्थ अधिक होते हैं। यहाँ पर और भी उदाहरण दिए गए हैं, जो यहाँ पर Objective C के id प्रकार की व्याख्या कर रहे हैं

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