इसके स्ट्रिंग समतुल्य वस्तुनिष्ठ-सी टाइप-सी को परिवर्तित करें


141

यह मानते हुए कि मेरे पास .h फ़ाइल में इस प्रकार घोषित किया गया है:

typedef enum {
  JSON,
  XML,
  Atom,
  RSS
} FormatType;

मैं एक फ़ंक्शन का निर्माण करना चाहूंगा जो टाइप किए गए के संख्यात्मक मान को एक स्ट्रिंग में परिवर्तित करता है। उदाहरण के लिए, यदि संदेश [self toString:JSON]भेजा गया था; यह 'JSON' लौटाएगा।

समारोह कुछ इस तरह दिखेगा:

-(NSString *) toString:(FormatType)formatType {
  //need help here
  return [];
}

संयोग से, अगर मैं इस वाक्यविन्यास की कोशिश करता हूं

[self toString:FormatType.JSON];

टाइप करने के लिए टाइप करने के लिए विधि के लिए, मैं एक त्रुटि मिलता है। मैं क्या खो रहा हूँ?


समस्या के समाधान के लिए मेरे उत्तर को stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios पर देखें ।
BooTooMany

4
हो सकता है कि हमें एनम पर स्विफ्ट भाषा में एक हग देना चाहिए ।
इटाची

@ क्रेग: यहाँ समाधान है github.com/ndpiparava/ObjcEnumString
नितिन

बिना एनर्जी के एक कस्टम गेटर का उपयोग किए बिना एक समाधान के लिए, जो स्ट्रिंग में कनवर्ट करता है, स्ट्रिंग-कास्ट मैक्रो सरणी देखें: stackoverflow.com/a/53755377/2057171
अल्बर्ट रेनशॉ

जवाबों:


135

यह वास्तव में एक सी प्रश्न है, जो ऑब्जेक्टिव-सी (जो सी भाषा का सुपरसेट है) के लिए विशिष्ट नहीं है। C में Enums को पूर्णांक के रूप में दर्शाया गया है। तो आपको एक फ़ंक्शन लिखने की ज़रूरत है जो एक एनम मूल्य दिए गए स्ट्रिंग को लौटाता है। इसे करने के कई तरीके हैं। स्ट्रिंग्स की एक सरणी जैसे कि एनम वैल्यू को इंडेक्स के रूप में एरे या मैप स्ट्रक्चर (जैसे NSDictionary) में इस्तेमाल किया जा सकता है जो एक स्ट्रिंग वर्क के लिए एनम वैल्यू को मैप करता है, लेकिन मुझे लगता है कि ये एप्रोच एक फंक्शन की तरह स्पष्ट नहीं हैं। रूपांतरण को स्पष्ट करता है (और सरणी दृष्टिकोण, हालांकि क्लासिक Cतरीका खतरनाक है यदि आपके ईनम मान 0 से दूषित नहीं हैं)। कुछ इस तरह काम करेगा:

- (NSString*)formatTypeToString:(FormatType)formatType {
    NSString *result = nil;

    switch(formatType) {
        case JSON:
            result = @"JSON";
            break;
        case XML:
            result = @"XML";
            break;
        case Atom:
            result = @"Atom";
            break;
        case RSS:
            result = @"RSS";
            break;
        default:
            [NSException raise:NSGenericException format:@"Unexpected FormatType."];
    }

    return result;
}

Enum मान के लिए सही सिंटैक्स के बारे में आपका संबंधित प्रश्न यह है कि आप केवल मान (उदाहरण JSON) का उपयोग करते हैं, न कि FormatType.JSONसाइटैक्स का। FormatTypeएक प्रकार और enum मान (जैसे है JSON, XMLआदि) मूल्यों है कि आप उस प्रकार को असाइन कर सकते हैं।


127

आप इसे आसानी से नहीं कर सकते। सी और ऑब्जेक्टिव-सी में, एनम वास्तव में केवल पूर्णांक स्थिरांक हैं। आपको स्वयं नामों की एक तालिका बनानी होगी (या कुछ प्रीप्रोसेसर दुरुपयोग के साथ)। उदाहरण के लिए:

// In a header file
typedef enum FormatType {
    JSON,
    XML,
    Atom,
    RSS
} FormatType;

extern NSString * const FormatType_toString[];

// In a source file
// initialize arrays with explicit indices to make sure 
// the string match the enums properly
NSString * const FormatType_toString[] = {
    [JSON] = @"JSON",
    [XML] = @"XML",
    [Atom] = @"Atom",
    [RSS] = @"RSS"
};
...
// To convert enum to string:
NSString *str = FormatType_toString[theEnumValue];

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

यह भी ध्यान दें कि यह मानता है कि आपके पास एक वैध एनम स्थिरांक है। यदि आपके पास एक अविश्वसनीय स्रोत से पूर्णांक मान है, तो आपको अतिरिक्त रूप से यह जांचने की आवश्यकता है कि आपका स्थिरांक वैध है, उदाहरण के लिए आपके एनम में "पिछले अधिकतम" मान को शामिल करके, या यह जाँच करके कि यह सरणी की लंबाई से कम है या नहीं sizeof(FormatType_toString) / sizeof(FormatType_toString[0])


37
आप स्पष्ट सूचकांकों के साथ सरणियों को इनिशियलाइज़ कर सकते हैं, उदाहरण के string[] = { [XML] = "XML" }लिए सुनिश्चित करें कि स्ट्रिंग ठीक से एनमों से मेल खाती है
क्रिस्टोफ़

@ क्रिसटोफ: हां, यह एक C99 फीचर है जिसे नामित इनिशियलाइज़र कहा जाता है । ऑब्जेक्टिव-सी (जो कि C99 पर आधारित है) में उपयोग करना ठीक है, लेकिन जेनेरिक C89 कोड के लिए, आप उन का उपयोग नहीं कर सकते।
एडम रोसेनफील्ड

क्या कोई रास्ता नहीं है दूसरे रास्ते से जाने का? उदाहरण के लिए, एनम को एक स्ट्रिंग दिया जाता है?
जम्मो

1
@Jameo: हाँ, लेकिन यह एक सरणी लुकअप करने में उतना सरल नहीं है। आपको या तो FormatType_toString[]सरणी के माध्यम से पुनरावृत्त करना होगा और -isEqualToString:प्रत्येक तत्व को एक मैच खोजने के लिए कॉल करना होगा, या एक डेटा मैपिंग का उपयोग करना होगा जैसे NSDictionaryकि उलटा लुकअप मैप बनाए रखने के लिए।
एडम रोसेनफील्ड

1
मैक्स ओ की चाल FormatType_toStringसरणी में प्रविष्टियों को जोड़ने के बारे में भूलने के लिए अच्छा है ।
एकोएलियू

50

मेरे समाधान:

संपादित करें: मैं अंत में भी एक बेहतर समाधान जोड़ दिया है, आधुनिक Obj सी का उपयोग कर

1.
एक सरणी में कुंजी के रूप में रखें नाम।
सुनिश्चित करें कि अनुक्रमणिकाएं उपयुक्त एनम हैं, और सही क्रम में हैं (अन्यथा अपवाद)।
नोट: नाम * _names * के रूप में संश्लेषित एक संपत्ति है;

संकलन के लिए कोड की जाँच नहीं की गई थी, लेकिन मैंने अपने ऐप में उसी तकनीक का उपयोग किया था।

typedef enum {
  JSON,
  XML,
  Atom,
  RSS
} FormatType;

+ (NSArray *)names
{
    static NSMutableArray * _names = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _names = [NSMutableArray arrayWithCapacity:4];
        [_names insertObject:@"JSON" atIndex:JSON];
        [_names insertObject:@"XML" atIndex:XML];
        [_names insertObject:@"Atom" atIndex:Atom];
        [_names insertObject:@"RSS" atIndex:RSS];
    });

    return _names;
}

+ (NSString *)nameForType:(FormatType)type
{
    return [[self names] objectAtIndex:type];
}


//

2.
आधुनिक ओबज-सी का उपयोग करके आप एनुम में चाबियों के विवरणों को टाई करने के लिए एक शब्दकोश का उपयोग कर सकते हैं।
आदेश नहीं होता है

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeParent = 0,
    UserTypeStudent = 1,
    UserTypeTutor = 2,
    UserTypeUnknown = NSUIntegerMax
};  

@property (nonatomic) UserType type;

+ (NSDictionary *)typeDisplayNames
{
    return @{@(UserTypeParent) : @"Parent",
             @(UserTypeStudent) : @"Student",
             @(UserTypeTutor) : @"Tutor",
             @(UserTypeUnknown) : @"Unknown"};
}

- (NSString *)typeDisplayName
{
    return [[self class] typeDisplayNames][@(self.type)];
}


उपयोग (कक्षा उदाहरण विधि में):

NSLog(@"%@", [self typeDisplayName]);



12
ध्यान रहे कि हर बार जब आप कॉल +[typeDisplayNames]करते हैं, तो आप शब्दकोश को फिर से बना रहे होते हैं। यह ठीक है अगर इसे केवल कुछ बार कहा जाता है, लेकिन अगर इसे कई बार कहा जाता है, तो यह बहुत महंगा हो जाएगा। शब्दकोश को एकल बनाने के लिए एक बेहतर समाधान हो सकता है, इसलिए यह केवल एक बार बनाया जाता है और अन्यथा स्मृति में रहता है। क्लासिक मेमोरी बनाम सीपीयू कोन्ड्रम।
जोएल फिशर

या इसे एक स्थिर चर के रूप में बदलें, उदाहरण के लिए static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;टिप्पणियाँ आपको लाइन को तोड़ने नहीं देंगी, इसके लिए क्षमा करें।
नटणवरा

29

@AdamRosenfield उत्तर, @Christoph टिप्पणी और एक अन्य चाल का संयोजन सादा सी enums को संभालने के लिए मैं सुझाव देता हूं:

// In a header file
typedef enum {
  JSON = 0,         // explicitly indicate starting index
  XML,
  Atom,
  RSS,

  FormatTypeCount,  // keep track of the enum size automatically
} FormatType;
extern NSString *const FormatTypeName[FormatTypeCount];


// In a source file
NSString *const FormatTypeName[FormatTypeCount] = {
  [JSON] = @"JSON",
  [XML] = @"XML",
  [Atom] = @"Atom",
  [RSS] = @"RSS",
};


// Usage
NSLog(@"%@", FormatTypeName[XML]);

सबसे खराब स्थिति में - जैसे कि यदि आप एनम को बदलते हैं, लेकिन नाम सरणी को बदलना भूल जाते हैं - तो यह इस कुंजी के लिए शून्य हो जाएगा।


12

क्लास हेडर में टाइपफाइफ एनम को परिभाषित करें:

typedef enum {
    IngredientType_text  = 0,
    IngredientType_audio = 1,
    IngredientType_video = 2,
    IngredientType_image = 3
} IngredientType;

कक्षा में इस तरह एक विधि लिखें:

+ (NSString*)typeStringForType:(IngredientType)_type {
   NSString *key = [NSString stringWithFormat:@"IngredientType_%i", _type];
   return NSLocalizedString(key, nil);
}

Localizable.strings फ़ाइल के अंदर तार हैं :

/* IngredientType_text */
"IngredientType_0" = "Text";
/* IngredientType_audio */
"IngredientType_1" = "Audio";
/* IngredientType_video */
"IngredientType_2" = "Video";
/* IngredientType_image */
"IngredientType_3" = "Image";

11

मैं संकलक के # स्ट्रिंग टोकन (मैक्रोज़ के साथ इसे और अधिक कॉम्पैक्ट बनाने के लिए) का उपयोग करूंगा:

#define ENUM_START              \
            NSString* ret;      \
            switch(value) {

#define ENUM_CASE(evalue)       \
            case evalue:        \
                ret = @#evalue; \
                break;

#define ENUM_END                \
            }                   \
            return ret;

NSString*
_CvtCBCentralManagerStateToString(CBCentralManagerState value)
{
    ENUM_START
        ENUM_CASE(CBCentralManagerStateUnknown)
        ENUM_CASE(CBCentralManagerStateResetting)
        ENUM_CASE(CBCentralManagerStateUnsupported)
        ENUM_CASE(CBCentralManagerStateUnauthorized)
        ENUM_CASE(CBCentralManagerStatePoweredOff)
        ENUM_CASE(CBCentralManagerStatePoweredOn)
    ENUM_END
}

C99 में इसने बहुत अच्छा काम किया - मैं C पर नया हूँ, और मैंने इस सवाल को पूरा करने का सबसे साफ तरीका पाया। मैंने उन वस्तुओं के लिए अपने कार्यान्वयन में एक डिफ़ॉल्ट रूप से जोड़ा है जिन्हें परिभाषित नहीं किया जा सकता है। बहुत साफ विधि। परिणामों के लिए धन्यवाद। मैक्रो का बहुत चालाक उपयोग।
ट्रैविसवाइड

8

मुझे यह #defineकरने का तरीका पसंद है :

// इसे अपनी .h फ़ाइल में, @interface ब्लॉक के बाहर रखें

typedef enum {
    JPG,
    PNG,
    GIF,
    PVR
} kImageType;
#define kImageTypeArray @"JPEG", @"PNG", @"GIF", @"PowerVR", nil

// Place this in the .m file, inside the @implementation block
// A method to convert an enum to string
-(NSString*) imageTypeEnumToString:(kImageType)enumVal
{
    NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
    return [imageTypeArray objectAtIndex:enumVal];
}

स्रोत (स्रोत अब उपलब्ध नहीं है)


@ दैय -जवान nilअगर वापस लौटने के बारे में क्या array.count <= enumValue?
anneblue

@anneblue जो त्रुटि को पकड़ लेगा .. यह नाजुक होगा क्योंकि यदि आप एक एनम वैल्यू जोड़ते हैं या एनम वैल्यू के पूर्णांक मान में परिवर्तन होता है तो यह गलत हो जाता है। स्वीकार किया गया उत्तर अच्छा होगा
दाइज-जिन-

@codercat :( क्षमा करें - निश्चित नहीं कि उस वेबसाइट का क्या हुआ। वे बैक में नहीं जब मशीन या तो ...
lindon fox

उपरोक्त उत्तर पर मेरा एक छोटा सा प्रश्न है। स्ट्रिंग तत्व को kImageType में कैसे परिवर्तित करें। मुझे स्ट्रिंग को पास करके imageTypeEnumToString विधि को कॉल करने की आवश्यकता है। क्या आप कृपया मेरी समस्या के लिए मेरी मदद कर सकते हैं।
गणेश

1
मुझे यह उत्तर सबसे अच्छा लगता है, क्योंकि आपके पास Enums के ठीक बगल में स्ट्रिंग परिभाषाएँ हैं। एक मान लापता होने का कम से कम मौका। और @ गणेश, कच्चे मूल्य से परिवर्तित करने के लिए, यह कर सकता है: रिटर्न (kImageType) [imageTypeArray indexOfObject: rawValue];
हैरिस

8

मैंने इस पेज पर मेरा बनाने के लिए पाए गए सभी समाधानों का मिश्रण बनाया, यह एक तरह का ऑब्जेक्ट ओरिएंटेड एनम एक्सटेंशन या कुछ और है।

वास्तव में यदि आपको केवल स्थिरांक (यानी पूर्णांक) से अधिक की आवश्यकता है, तो आपको संभवतः एक मॉडल ऑब्जेक्ट की आवश्यकता है (हम सभी के बारे में बात कर रहे हैं? सही है?)

बस इसका उपयोग करने से पहले अपने आप से सवाल पूछें, क्या मैं सही हूं, क्या आप वास्तव में, एक वास्तविक मॉडल वस्तु की जरूरत नहीं है, एक webservice, एक plist, एक SQLite डेटाबेस या CoreData से initialized?

वैसे भी यहाँ कोड आता है (MPI "माय प्रोजेक्ट इनिशियल्स" के लिए है, हर कोई इस या उनके नाम का उपयोग करता है, ऐसा लगता है):

MyWonderfulType.h :

typedef NS_ENUM(NSUInteger, MPIMyWonderfulType) {
    MPIMyWonderfulTypeOne = 1,
    MPIMyWonderfulTypeTwo = 2,
    MPIMyWonderfulTypeGreen = 3,
    MPIMyWonderfulTypeYellow = 4,
    MPIMyWonderfulTypePumpkin = 5
};

#import <Foundation/Foundation.h>

@interface MyWonderfulType : NSObject

+ (NSString *)displayNameForWonderfulType:(MPIMyWonderfulType)wonderfulType;
+ (NSString *)urlForWonderfulType:(MPIMyWonderfulType)wonderfulType;

@end

और MyWonderfulType.m:

#import "MyWonderfulType.h"

@implementation MyWonderfulType

+ (NSDictionary *)myWonderfulTypeTitles
{
    return @{
             @(MPIMyWonderfulTypeOne) : @"One",
             @(MPIMyWonderfulTypeTwo) : @"Two",
             @(MPIMyWonderfulTypeGreen) : @"Green",
             @(MPIMyWonderfulTypeYellow) : @"Yellow",
             @(MPIMyWonderfulTypePumpkin) : @"Pumpkin"
             };
}

+ (NSDictionary *)myWonderfulTypeURLs
{
    return @{
             @(MPIMyWonderfulTypeOne) : @"http://www.theone.com",
             @(MPIMyWonderfulTypeTwo) : @"http://www.thetwo.com",
             @(MPIMyWonderfulTypeGreen) : @"http://www.thegreen.com",
             @(MPIMyWonderfulTypeYellow) : @"http://www.theyellow.com",
             @(MPIMyWonderfulTypePumpkin) : @"http://www.thepumpkin.com"
             };
}

+ (NSString *)displayNameForWonderfulType:(MPIMyWonderfulType)wonderfulType {
    return [MPIMyWonderfulType myWonderfulTypeTitles][@(wonderfulType)];
}

+ (NSString *)urlForWonderfulType:(MPIMyWonderfulType)wonderfulType {
    return [MPIMyWonderfulType myWonderfulTypeURLs][@(wonderfulType)];
}


@end

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

5

एक और समाधान:

typedef enum BollettinoMavRavTypes {
    AMZCartServiceOperationCreate,
    AMZCartServiceOperationAdd,
    AMZCartServiceOperationGet,
    AMZCartServiceOperationModify
} AMZCartServiceOperation;

#define AMZCartServiceOperationValue(operation) [[[NSArray alloc] initWithObjects: @"CartCreate", @"CartAdd", @"CartGet", @"CartModify", nil] objectAtIndex: operation];

अपनी विधि में आप उपयोग कर सकते हैं:

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

स्ट्रिंग निर्भरता को गिराकर @ yar1vn उत्तर में सुधार:

#define VariableName(arg) (@""#arg)

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeParent = 0,
    UserTypeStudent = 1,
    UserTypeTutor = 2,
    UserTypeUnknown = NSUIntegerMax
};  

@property (nonatomic) UserType type;

+ (NSDictionary *)typeDisplayNames
{
    return @{@(UserTypeParent) : VariableName(UserTypeParent),
             @(UserTypeStudent) : VariableName(UserTypeStudent),
             @(UserTypeTutor) : VariableName(UserTypeTutor),
             @(UserTypeUnknown) : VariableName(UserTypeUnknown)};
}

- (NSString *)typeDisplayName
{
    return [[self class] typeDisplayNames][@(self.type)];
}

इस प्रकार जब आप एनम एंट्री नेम को बदलेंगे तो संबंधित स्ट्रिंग को बदल दिया जाएगा। यदि आप इस स्ट्रिंग को उपयोगकर्ता को दिखाने नहीं जा रहे हैं तो उपयोगी है।


क्या आप समझा सकते हैं "- परिवर्तनीय नाम परिभाषित करें (arg) (@" "# arg) --- और शायद बेहतर समाधान दे?
xySVerma

#Defines के साथ, जब आप एक प्रतिस्थापन के लिए # का उपयोग करते हैं, तो तर्क स्वचालित रूप से दोहरे उद्धरण चिह्नों में लिपटा होता है। सी में, जब कोड में दो तार एक दूसरे के बगल में दिखाई देते हैं "foo""bar", जैसे "foobar"कि संकलित होने पर स्ट्रिंग में परिणाम होता है। तो, #define VariableName(arg) (@""#arg)विस्तार VariableName(MyEnum)होगा (@"""MyEnum")। जिसके परिणामस्वरूप स्ट्रिंग होगा @"MyEnum"
क्रिस डगलस

3

एक एनुम परिभाषा को देखते हुए जैसे:

typedef NS_ENUM(NSInteger, AssetIdentifier) {
    Isabella,
    William,
    Olivia
};

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

#define AssetIdentifier(asset) \
^(AssetIdentifier identifier) { \
switch (identifier) { \
case asset: \
default: \
return @#asset; \
} \
}(asset)

switchबयान ब्लॉक में इस्तेमाल किया प्रकार की जाँच के लिए है, और यह भी Xcode में स्वत: पूर्ण समर्थन प्राप्त करने के।

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें


2

मेरे पास एक बड़ा गणना प्रकार था जिसे मैं इसे एक NSDictionaryलुकअप में बदलना चाहता था । मैंने sedOSX टर्मिनल का उपयोग इस प्रकार किया:

$ sed -E 's/^[[:space:]]{1,}([[:alnum:]]{1,}).*$/  @(\1) : @"\1",/g' ObservationType.h

जिसे इस रूप में पढ़ा जा सकता है: 'लाइन और आउटपुट पर पहला शब्द कैप्चर करें @ (शब्द): @ "शब्द",'

यह रेगेक्स 'ऑब्जर्वेशन टाइप' नामक एक हेडर फाइल में एनम को परिवर्तित करता है जिसमें शामिल हैं:

typedef enum : int { 
    ObservationTypePulse = 1,
    ObservationTypeRespRate = 2,
    ObservationTypeTemperature = 3,
    .
    .
}

कुछ इस तरह से:

    @(ObservationTypePulse) : @"ObservationTypePulse",
    @(ObservationTypeRespRate) : @"ObservationTypeRespRate",
    @(ObservationTypeTemperature) : @"ObservationTypeTemperature",
    .
    .

जिसे फिर लुकअप @{ }बनाने के लिए आधुनिक ऑब्जेक्टिव-सी सिंटैक्स (जैसा कि @ yar1vn द्वारा ऊपर बताया गया है) का उपयोग करके विधि में लपेटा जा सकता है NSDictionary:

-(NSDictionary *)observationDictionary
{
    static NSDictionary *observationDictionary;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        observationDictionary = [[NSDictionary alloc] initWithDictionary:@{
                                 @(ObservationTypePulse) : @"ObservationTypePulse",
                                 @(ObservationTypeRespRate) : @"ObservationTypeRespRate",
                                 .
                                 .
                                 }];
    });
    return observationDictionary;
}

dispatch_onceबॉयलर-प्लेट सिर्फ यह सुनिश्चित करने की है कि स्थिर चर एक धागा सुरक्षित तरीके से initialised है।

नोट: मुझे OSX पर sed रेगेक्स एक्सप्रेशन अजीब मिला - जब मैंने +'एक या अधिक' से मेल खाने की कोशिश की तो यह काम नहीं किया और इसे {1,}प्रतिस्थापन के रूप में उपयोग करना पड़ा


2

मैं बैरी वॉक के उत्तर पर भिन्नता का उपयोग करता हूं, जो कि महत्व के क्रम में है:

  1. संकलक को गुम केस क्लॉज़ की जाँच करने की अनुमति देता है (यदि आपके पास डिफ़ॉल्ट क्लॉज़ है तो यह नहीं हो सकता है)।
  2. एक उद्देश्य-सी ठेठ नाम का उपयोग करता है (बजाय जावा नाम की तरह)।
  3. एक विशिष्ट अपवाद उठाता है।
  4. छोटा होता है।

ईजी:

- (NSString*)describeFormatType:(FormatType)formatType {    
    switch(formatType) {
        case JSON:
            return @"JSON";
        case XML:
            return @"XML";
        case Atom:
            return @"Atom";
        case RSS:
            return @"RSS";
    }
    [NSException raise:NSInvalidArgumentException format:@"The given format type number, %ld, is not known.", formatType];
    return nil; // Keep the compiler happy - does not understand above line never returns!
}

2

@pixel ने यहां सबसे शानदार जवाब जोड़ा: https://stackoverflow.com/a/24255387/1364257 कृपया, उसे अपग्रेड करें!

वह 1960 से स्वच्छ X मैक्रो का उपयोग करता है। (मैंने आधुनिक ओबजेक के लिए उसका कोड थोड़ा बदल दिया है)

#define X(a, b, c) a b,
enum ZZObjectType {
    XXOBJECTTYPE_TABLE
};
typedef NSUInteger TPObjectType;
#undef X

#define XXOBJECTTYPE_TABLE \
X(ZZObjectTypeZero, = 0, @"ZZObjectTypeZero") \
X(ZZObjectTypeOne, , @"ZZObjectTypeOne") \
X(ZZObjectTypeTwo, , @"ZZObjectTypeTwo") \
X(ZZObjectTypeThree, , @"ZZObjectTypeThree")

+ (NSString*)nameForObjectType:(ZZObjectType)objectType {
#define X(a, b, c) @(a):c, 
    NSDictionary *dict = @{XXOBJECTTYPE_TABLE};
#undef X
    return dict[objectType];
}

बस। साफ और सुथरा। @Pixel को धन्यवाद! https://stackoverflow.com/users/21804/pixel


@AlexandreG आपका समाधान प्रदान करता है, आदमी। किसी पर कार्प करना आसान है। इस समाधान में इसके स्पष्ट पक्ष और स्पष्ट सहमति दोनों हैं। अपने समाधान से दुनिया को बेहतर बनाओ।
वॉइगर

2

मैंने यहां कई दृष्टिकोणों को संयुक्त किया। मुझे प्रीप्रोसेसर और अनुक्रमित सूची का विचार पसंद है।

कोई अतिरिक्त डायनेमिक आवंटन नहीं है, और कंपाइलर इनलाइनिंग के कारण लुकअप को ऑप्टिमाइज़ करने में सक्षम हो सकता है।

typedef NS_ENUM(NSUInteger, FormatType) { FormatTypeJSON = 0, FormatTypeXML, FormatTypeAtom, FormatTypeRSS, FormatTypeCount };

NS_INLINE NSString *FormatTypeToString(FormatType t) {
  if (t >= FormatTypeCount)
    return nil;

#define FormatTypeMapping(value) [value] = @#value

  NSString *table[FormatTypeCount] = {FormatTypeMapping(FormatTypeJSON),
                                      FormatTypeMapping(FormatTypeXML),
                                      FormatTypeMapping(FormatTypeAtom),
                                      FormatTypeMapping(FormatTypeRSS)};

#undef FormatTypeMapping

  return table[t];
}

1

सबसे पहले, FormatType.JSON के संबंध में: JSON FormatType का सदस्य नहीं है, यह प्रकार का संभावित मान है। FormatType एक समग्र प्रकार भी नहीं है - यह एक अदिश राशि है।

दूसरा, ऐसा करने का एकमात्र तरीका एक मानचित्रण तालिका बनाना है। ऑब्जेक्टिव-सी में ऐसा करने का अधिक सामान्य तरीका आपके "प्रतीकों" का संदर्भ देते हुए स्थिरांक की एक श्रृंखला बनाना है, इसलिए आपके पास हैNSString *FormatTypeJSON = @"JSON" ऐसा ही हो।


1

निम्नलिखित एक समाधान प्रदान करता है जैसे कि एक नई एनम को जोड़ने के लिए केवल एक-लाइन एडिट की आवश्यकता होती है, इसी तरह का काम एनम {} सूची में सिंगल लाइन को जोड़ने के लिए होता है।

//------------------------------------------------------------------------------
// enum to string example
#define FOR_EACH_GENDER(tbd) \
        tbd(GENDER_MALE) \
        tbd(GENDER_FEMALE) \
        tbd(GENDER_INTERSEX) \

#define ONE_GENDER_ENUM(name) name,
enum
{
    FOR_EACH_GENDER(ONE_GENDER_ENUM)
    MAX_GENDER
};

#define ONE_GENDER(name) #name,
static const char *enumGENDER_TO_STRING[] = 
{
    FOR_EACH_GENDER(ONE_GENDER)
};

// access string name with enumGENDER_TO_STRING[value]
// or, to be safe converting from a untrustworthy caller
static const char *enumGenderToString(unsigned int value)
{
    if (value < MAX_GENDER)
    {
        return enumGENDER_TO_STRING[value];
    }
    return NULL;
}

static void printAllGenders(void)
{
    for (int ii = 0;  ii < MAX_GENDER;  ii++)
    {
        printf("%d) gender %s\n", ii, enumGENDER_TO_STRING[ii]);
    }
}

//------------------------------------------------------------------------------
// you can assign an arbitrary value and/or information to each enum,
#define FOR_EACH_PERSON(tbd) \
        tbd(2, PERSON_FRED,     "Fred",     "Weasley", GENDER_MALE,   12) \
        tbd(4, PERSON_GEORGE,   "George",   "Weasley", GENDER_MALE,   12) \
        tbd(6, PERSON_HARRY,    "Harry",    "Potter",  GENDER_MALE,   10) \
        tbd(8, PERSON_HERMIONE, "Hermione", "Granger", GENDER_FEMALE, 10) \

#define ONE_PERSON_ENUM(value, ename, first, last, gender, age) ename = value,
enum
{
    FOR_EACH_PERSON(ONE_PERSON_ENUM)
};

typedef struct PersonInfoRec
{
    int value;
    const char *ename;
    const char *first;
    const char *last;
    int gender;
    int age;
} PersonInfo;

#define ONE_PERSON_INFO(value, ename, first, last, gender, age) \
                     { ename, #ename, first, last, gender, age },
static const PersonInfo personInfo[] = 
{
    FOR_EACH_PERSON(ONE_PERSON_INFO)
    { 0, NULL, NULL, NULL, 0, 0 }
};
// note: if the enum values are not sequential, you need another way to lookup
// the information besides personInfo[ENUM_NAME]

static void printAllPersons(void)
{
    for (int ii = 0;  ;  ii++)
    {
        const PersonInfo *pPI = &personInfo[ii];
        if (!pPI->ename)
        {
            break;
        }
        printf("%d) enum %-15s  %8s %-8s %13s %2d\n",
            pPI->value, pPI->ename, pPI->first, pPI->last,
            enumGenderToString(pPI->gender), pPI->age);
    }
}

इस तकनीक को एक्स-मैक्रो कहा जाता है, अगर कोई इसके बारे में पढ़ना चाहता है। यह इस तथ्य से आता है कि, परंपरागत रूप से, FOR_EACH_GENDER () मैक्रो को हमेशा एक्स () कहा जाता था। इससे पहले कि आप इसे नए अर्थ के साथ पुनर्निर्धारित करने से पहले एक बात आप करना चाहते हैं वह है #undef FOR_EACH_GENDER।
१०:५६

1

यहां हर उत्तर मूल रूप से एक ही बात कहता है, एक नियमित एनम बनाएं और फिर स्ट्रिंग्स के बीच स्विच करने के लिए एक कस्टम गेटर का उपयोग करें।

मैं मैक्रो का उपयोग करते हुए बहुत अधिक सरल, अधिक सरल और छोटे क्लीनर को नियोजित करता हूं!


#define kNames_allNames ((NSArray <NSString *> *)@[@"Alice", @"Bob", @"Eve"])
#define kNames_alice ((NSString *)kNames_allNames[0])
#define kNames_bob ((NSString *)kNames_allNames[1])
#define kNames_eve ((NSString *)kNames_allNames[2])

फिर आप बस टाइप करना शुरू कर सकते हैं kNam... और स्वतः पूर्ण आप इच्छा सूची प्रदर्शित करेगा!

इसके अतिरिक्त, यदि आप एक ही बार में सभी नामों के लिए तर्क को संभालना चाहते हैं, तो आप इस प्रकार से क्रमिक रूप से शाब्दिक सरणी को तेजी से बढ़ा सकते हैं:

for (NSString *kName in kNames_allNames) {}

अंत में, मैक्रोज़ में NSString कास्टिंग टाइपफेड के समान व्यवहार सुनिश्चित करता है!


का आनंद लें!


0

कई जवाब सभी काफी अच्छे हैं।

यदि आप एक सामान्य, वस्तुनिष्ठ सी समाधान के बाद हैं जो कुछ मैक्रोज़ का उपयोग करता है ...

मुख्य विशेषता यह है कि एनएसएस का उपयोग एनएसएसटीरिंग स्थिरांक के स्थिर सरणी में एक सूचकांक के रूप में किया जाता है। सरणी खुद को एक फ़ंक्शन में लपेटा जाता है ताकि इसे Apple API में प्रचलित NSStringFromXXX फ़ंक्शंस के सूट की तरह बनाया जा सके।

आपको #import "NSStringFromEnum.h"यहां http://pastebin.com/u83RR3Vk ढूंढना होगा

[EDIT] को #import "SW+Variadic.h"यहां http://pastebin.com/UEqTzYLf की भी आवश्यकता है

उदाहरण 1: स्ट्रिंग कन्वर्टर्स के साथ पूरी तरह से एक नया एनम टाइप टाइप परिभाषित करें।

myfile.h में


 #import "NSStringFromEnum.h"

 #define define_Dispatch_chain_cmd(enum)\
 enum(chain_done,=0)\
 enum(chain_entry)\
 enum(chain_bg)\
 enum(chain_mt)\
 enum(chain_alt)\
 enum(chain_for_c)\
 enum(chain_while)\
 enum(chain_continue_for)\
 enum(chain_continue_while)\
 enum(chain_break_for)\
 enum(chain_break_while)\
 enum(chain_previous)\
 enum(chain_if)\
 enum(chain_else)\


interface_NSString_Enum_DefinitionAndConverters(Dispatch_chain_cmd)

myfile.m में:


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

उपयोग करने के लिए :

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) रिटर्न @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") रिटर्न chain_previous

उदाहरण 2: एक मौजूदा एनम के लिए रूपांतरण सेटिंग्स प्रदान करना भी एक सेटिंग स्ट्रिंग का उपयोग करके प्रदर्शित करता है, और फ़ंक्शन में उपयोग किए गए टाइपनाम का नाम बदल रहा है।

myfile.h में


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

myfile.m में:


 // we can put this in the .m file as we are not defining a typedef, just the strings.
 #define define_CAEdgeAntialiasingMask(enum)\
 enum(kCALayerLeftEdge)\
 enum(kCALayerRightEdge)\
 enum(kCALayerBottomEdge)\
 enum(kCALayerTopEdge)



 implementation_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

0

यहाँ काम कर रहा है -> https://github.com/ndpiparava/ObjcEnumString

//1st Approach
#define enumString(arg) (@""#arg)

//2nd Approach

+(NSString *)secondApproach_convertEnumToString:(StudentProgressReport)status {

    char *str = calloc(sizeof(kgood)+1, sizeof(char));
    int  goodsASInteger = NSSwapInt((unsigned int)kgood);
    memcpy(str, (const void*)&goodsASInteger, sizeof(goodsASInteger));
    NSLog(@"%s", str);
    NSString *enumString = [NSString stringWithUTF8String:str];
    free(str);

    return enumString;
}

//Third Approcah to enum to string
NSString *const kNitin = @"Nitin";
NSString *const kSara = @"Sara";


typedef NS_ENUM(NSUInteger, Name) {
    NameNitin,
    NameSara,
};

+ (NSString *)thirdApproach_convertEnumToString :(Name)weekday {

    __strong NSString **pointer = (NSString **)&kNitin;
    pointer +=weekday;
    return *pointer;
}

के बाद से डुप्लिकेट जवाब की अनुमति नहीं है, यहाँ पूर्ण समाधान है github.com/ndpiparava/ObjcEnumString
नितिन

-2

अपनी आवश्यकताओं के आधार पर, आप वैकल्पिक रूप से संकलक निर्देशों का उपयोग कर सकते हैं, जिस व्यवहार की तलाश कर रहे हैं।

 #define JSON @"JSON"
 #define XML @"XML"
 #define Atom @"Atom"
 #define RSS @"RSS"

बस सामान्य संकलक कमियों को याद रखें, (सुरक्षित प्रकार नहीं, प्रत्यक्ष प्रति-पेस्ट स्रोत फ़ाइल को बड़ा बनाता है)


8
मुझे नहीं लगता कि यह काम करेगा; कहीं भी #defineदिखाई देने पर, आप वास्तविक एनम मान का उपयोग करने में सक्षम नहीं होंगे (यानी प्रीप्रोसेसर द्वारा JSONप्रतिस्थापित किया @"JSON"जाएगा और जब एक असाइन करने में कंपाइलर त्रुटि होगी FormatType
बैरी वार्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.