ऑब्जेक्टिव-सी में एक टाइप्डम एनम क्या है?


1087

मुझे नहीं लगता कि मैं मौलिक रूप से समझता हूं कि क्या enumहै, और इसका उपयोग कब करना है।

उदाहरण के लिए:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

यहाँ वास्तव में क्या घोषित किया जा रहा है?


2
क्या उपयोगकर्ता परिभाषित प्रकार को "एनम" कहा जाता है? यही मैंने सोचा था, जब तक कि मैं कोड भर में नहीं आया था, जिसमें कई टाइप किए गए Enum घोषणाएं थीं।
क्रेग

8
नहींं, उपयोगकर्ता परिभाषित प्रकार शेप टाइप है। Typedef पर पढ़ें: en.wikipedia.org/wiki/Typedef
rampion

6
Objective-C में एक Typeedef, C. में एक Typeedef के समान है। 2, और एनम को आकार टाइप नाम देता है। यदि आप नहीं जानते हैं कि "टाइपडेफ" और "
एनम

जवाबों:


1565

तीन बातें यहाँ घोषित किया जा रहा है: एक गुमनाम enumerated प्रकार घोषित किया जाता है, ShapeTypeअनाम गणन के लिए एक typedef घोषित किया जा रहा है, और तीन नामों kCircle, kRectangleऔर kOblateSpheroidअभिन्न स्थिरांक के रूप में घोषित किया जा रहा है।

चलो कि नीचे तोड़ो। सबसे सरल मामले में, एक गणना के रूप में घोषित किया जा सकता है

enum tagname { ... };

यह टैग के साथ एक गणना की घोषणा करता है tagname। C और ऑब्जेक्टिव-सी (लेकिन C ++ नहीं ) में, इस से संबंधित किसी भी संदर्भ को कीवर्ड से पहले होना चाहिए enum। उदाहरण के लिए:

enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++

enumहर जगह कीवर्ड का उपयोग करने से बचने के लिए , एक टाइप-बी बनाया जा सकता है:

enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'

इसे एक पंक्ति में सरल बनाया जा सकता है:

typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'

और अंत में, अगर हमें कीवर्ड के enum tagnameसाथ उपयोग करने में सक्षम होने की आवश्यकता नहीं है, तो हम अनाम enumबना सकते हैं enumऔर केवल इसे टाइपराइंड के साथ घोषित कर सकते हैं :

typedef enum { ... } tagname;

अब, इस मामले में, हम ShapeTypeएक गुमनाम संस्मरण का टाइपडिफेड नाम घोषित कर रहे हैं । ShapeTypeवास्तव में सिर्फ एक अभिन्न प्रकार है, और केवल चर जो घोषणा में सूचीबद्ध मानों में से एक (है कि, में से एक पकड़ घोषित करने के लिए इस्तेमाल किया जाना चाहिए kCircle, kRectangleऔर kOblateSpheroid)। आप एक ShapeTypeवैरिएबल को किसी अन्य मान को कास्टिंग द्वारा असाइन कर सकते हैं , हालांकि, एनम मूल्यों को पढ़ते समय आपको सावधान रहना होगा।

अंत में, kCircle, kRectangle, और kOblateSpheroidग्लोबल नेम स्पेस में अभिन्न स्थिरांक के रूप में घोषित कर रहे हैं। चूंकि कोई विशिष्ट मान निर्दिष्ट नहीं किया गया था, वे 0 से शुरू होने वाले लगातार पूर्णांक को असाइन किए जाते हैं, इसलिए kCircle0 है, kRectangle1 है, और kOblateSpheroid2 है।


6
अच्छा स्पष्टीकरण - बस एक चीज जोड़ने के लिए, सी में संरचना के समान नामकरण नियमों का पालन करें (उद्देश्य-सी के बारे में निश्चित नहीं)।
माइकल बूर

109
Objective-C, C का एक उचित सुपरसेट है। C में सभी C संरचना नामकरण नियम Object-C में ही मान्य हैं।
सिगाजाइस

बहुत बढ़िया। क्या मैं सिर्फ C ++ शैली का उपयोग कर सकता हूं और मुझे enum लिखने की भी आवश्यकता नहीं है :)
user4951

11
यदि आप जिस फ़ाइल में उन्हें घोषित करते हैं, वह .m के बजाय .mm फ़ाइल है, तो आप C ++ शैली का उपयोग कर सकते हैं। उद्देश्य-सी ++ बेतुका शक्तिशाली है।
केविन हॉफमैन

14
और एक बार जब आप इस उत्तर के आसपास अपना सिर पा लेते हैं, तो यह नए NS_ENUM और NS_OPTIONS को देखने के लायक है। यहाँ ट्यूटोरियल: nshipster.com/ns_enum-ns_options और SO यहाँ: stackoverflow.com/questions/14080750/…
स्नोक्रैश

254

Apple Xcode 4.4 के बाद से इस तरह से परिभाषित करने की सिफारिश करता है :

typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

वे एक आसान मैक्रो प्रदान करते हैं NS_ENUM:

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

ये परिभाषाएँ मजबूत प्रकार की जाँच और बेहतर कोड पूर्ति प्रदान करती हैं। मुझे इसका आधिकारिक दस्तावेज नहीं मिला NS_ENUM, लेकिन आप WWDC 2012 के सत्र से "आधुनिक उद्देश्य-सी" वीडियो देख सकते हैं


अपडेट करें
यहाँ आधिकारिक दस्तावेज के लिए लिंक ।


13
"
एनम

5
जैसा कि एक अन्य उत्तर में टिप्पणी की NS_ENUMगई है, NSHipster द्वारा Apple के मैक्रो की व्याख्या देखें : NSHipster.com/ns_enum-ns_options
बेसिल बॉर्क


50

एक एनम क्रमबद्ध मानों के एक सेट की घोषणा करता है - टंकण इसके लिए एक आसान नाम जोड़ता है। पहला तत्व 0 है आदि।

typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

ऊपर सिर्फ आकार टैग का एक ज्ञान है।


34

एक उपयोगकर्ता परिभाषित प्रकार के संभावित मान है kCircle, kRectangleया kOblateSpheroid। एनम (kCircle, आदि) के अंदर के मान हालांकि, एनम के बाहर दिखाई देते हैं। यह ध्यान में रखना महत्वपूर्ण है ( int i = kCircle;उदाहरण के लिए मान्य है)।


30

64-बिट परिवर्तन के लिए अद्यतन: 64-बिट परिवर्तनों के बारे में सेब डॉक्स के अनुसार ,

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

तो अगर आप के लिए है प्रकार के साथ enum बनाने यदि आप 64-बिट के लिए समर्थन वाक्य रचना नीचे के रूप में।

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

या

typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

अन्यथा, यह चेतावनी के रूप में ले जाएगा Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

स्विफ्ट-प्रोग्रामिंग के लिए अपडेट:

स्विफ्ट में, एक सिंटैक्स परिवर्तन है।

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

अगर आपको एनम (NS_ENUM) घोषित करने की आवश्यकता है: stackoverflow.com/a/42009056/342794
lal

25

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

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };

इस एनम को अनाम कहा जाता है क्योंकि आपके पास इसे नाम देने के लिए कोई प्रतीक नहीं है। लेकिन यह अभी भी पूरी तरह से सही है। बस इसे ऐसे ही इस्तेमाल करें

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;

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

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;

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

फिर अगर आप कई जगहों पर एनुमरेटर्स (यहां xs ... xxxxl) के एक ही सेट को फिर से उपयोग करना चाहते हैं, तो आपको इसे एक अद्वितीय नाम के साथ टैग करना होगा। दूसरी बार जब आप इस सेट का उपयोग करेंगे तो आपको केवल टैग का उपयोग करना होगा। लेकिन यह मत भूलिए कि यह टैग एनम शब्द को प्रतिस्थापित नहीं करता है, बल्कि एन्यूमेरेटर्स के सेट को बदल देता है। फिर ध्यान रखें कि हमेशा की तरह एनम का उपयोग करें। ऐशे ही:

// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now!
enum sizes myGrandFatherPantSize;

आप इसे एक पैरामीटर परिभाषा में भी उपयोग कर सकते हैं:

// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;

आप कह सकते हैं कि हर जगह की गणना लिखना सुविधाजनक नहीं है और कोड थोड़ा अजीब लगता है। तुम सही हो। एक वास्तविक प्रकार बेहतर होगा।

यह शिखर सम्मेलन के लिए हमारी महान प्रगति का अंतिम चरण है। केवल एक टाइपफ़ेड जोड़कर हम अपने एनम को एक वास्तविक प्रकार में बदल देते हैं। अरे आखिरी बात, आपकी कक्षा के भीतर टाइप्डफ की अनुमति नहीं है। फिर ऊपर अपने प्रकार को परिभाषित करें। इसको ऐसे करो:

// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}

याद रखें कि टैग वैकल्पिक है। फिर यहाँ से, उस स्थिति में, हम एन्यूमरेटर्स को टैग नहीं करते हैं, बल्कि एक नए प्रकार को परिभाषित करते हैं। तब हमें वास्तव में इसकी कोई आवश्यकता नहीं है।

// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end

यदि आप XCode के साथ Objective-C में विकसित कर रहे हैं तो मैं आपको NS_ENUM के साथ उपसर्गित कुछ अच्छे मैक्रोज़ की खोज करने देता हूँ। आपको अच्छे एनमों को आसानी से परिभाषित करने में मदद करनी चाहिए और संकलन करने से पहले स्थैतिक विश्लेषक को आपके लिए कुछ दिलचस्प जांच करने में मदद मिलेगी।

अच्छा एनम!


मैंने हमेशा सोचा था कि "कोई भी एक सवाल का जवाब क्यों देगा जो पहले से ही उत्तर दिया गया है और स्वीकार किया गया है"। लड़का, मैं हर समय गलत था! यह सबसे अच्छा जवाब है और मेरी तरह शुरुआती लोगों की मदद करता है!
राकेशदेव १३'१

10

typedefमौजूदा चर प्रकार के नाम को फिर से परिभाषित करने के लिए उपयोगी है। यह डेटाटाइप को कॉल करने का छोटा और सार्थक तरीका प्रदान करता है। उदाहरण के लिए:

typedef unsigned long int TWOWORDS;

यहाँ, टाइप किए गए लंबे int को TWOWORDS के प्रकार से पुनर्परिभाषित किया जाता है। इस प्रकार, अब हम लिखित रूप से लंबे समय तक अप्रयुक्त प्रकार के चर घोषित कर सकते हैं,

TWOWORDS var1, var2;

के बजाय

unsigned long int var1, var2;

7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

तो आप इसे उपयोग कर सकते हैं जैसे: -

 ShapeType shape;

तथा

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

अब आप इसका उपयोग कर सकते हैं जैसे: -

enum ShapeType shape;

3

enum का उपयोग enum तत्वों को मान प्रदान करने के लिए किया जाता है जो संरचना में नहीं किया जा सकता है। इसलिए हर बार पूरा वैरिएबल एक्सेस करने के बजाय हम वैसा ही कर सकते हैं जैसा कि हम एनम में वेरिएबल्स को देते हैं। डिफ़ॉल्ट रूप से यह 0 असाइनमेंट के साथ शुरू होता है, लेकिन हम इसे किसी भी मान को असाइन कर सकते हैं और एनम में अगले वेरिएबल को पिछले मान +1 का मान दिया जाएगा।


3

आप नीचे प्रारूप में उपयोग कर सकते हैं, रॉ डिफ़ॉल्ट मान 0 से शुरू हो रहा है, इसलिए

  • kCircle 0 है,
  • kRectangle 1 है,
  • kOblateSpheroid 2 है।

आप अपना विशिष्ट आरंभिक मूल्य निर्दिष्ट कर सकते हैं।

typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0

2

एक टाइपराइफ़ प्रोग्रामर को एक ऑब्जेक्ट-सी प्रकार को दूसरे के रूप में परिभाषित करने की अनुमति देता है। उदाहरण के लिए,

typedef int काउंटर; प्रकार को परिभाषित करता है काउंटर इंट के प्रकार के बराबर है। यह काफी कोड पठनीयता में सुधार करता है।


2

टंकण सी और सी ++ में एक कीवर्ड है। इसका उपयोग बुनियादी डेटा प्रकारों (चार, इंट, फ्लोट, डबल, स्ट्रक्चर और एनम) के लिए नए नाम बनाने के लिए किया जाता है ।

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

यहां यह एन्यूमरेटेड डेटा टाइप शेप टाइप बनाता है और हम एनम टाइप शेप टाइप के लिए नए नाम लिख सकते हैं जैसा कि नीचे दिया गया है

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

1

enum कई प्रकार की "त्रुटियों" को कम कर सकता है और कोड को अधिक प्रबंधनीय बना सकता है

#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER

परिभाषा में कोई अड़चन नहीं है। यह केवल एक प्रतिस्थापन है। यह राज्य की सभी स्थितियों को सीमित करने में सक्षम नहीं है। जब स्टेट 5 को सौंपा जाता है, तो प्रोग्राम गलत होगा, क्योंकि कोई मिलान स्थिति नहीं है। लेकिन संकलक STATE = 5 को चेतावनी देने वाला नहीं है

इसलिए इस तरह का उपयोग करना बेहतर है

typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

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