2009-08-07 51 views
4

在XML中存儲枚舉並將其重新讀出的最簡單方法是什麼?說我有:在C枚舉和XML之間進行轉換

enum ETObjectType {ETNormalObjectType, ETRareObjectType, ETEssentialObjectType}; 

...我想採取一個變量,enum ETObjectType objectType = ETNormalObjectType;,並將其轉換爲XML,看起來像這樣:<objectType>ETNormalObjectType</objectType>

我在做什麼當前是這樣的:

NSString* const ETObjectTypeAsString[] = {@"ETNormalObjectType",@"ETRareObjectType",@"ETEssentialObjectType"}; 

[anXMLElement addChild:[NSXMLElement elementWithName:@"objectType" stringValue:ETObjectTypeAsString[objectType]]]; 

...但是這不完全理想;每次更改枚舉時,我都不滿意更新這兩個列表。但這是可以接受的。很多,更糟的是讀回XML,我目前正在這樣做:

if ([[[anXMLElement childNamed:@"objectType"] stringValue] isEqualToString:@"ETRareObjectType"]) 
{ 
    [self initObjectType:ETRareObjectType]; 
} 
else if ([[[anXMLElement childNamed:@"objectType"] stringValue] isEqualToString:@"ETEssentialObjectType"]) 
{ 
    [self initObjectType:ETEssentialObjectType]; 
} 
else 
{ 
    [self initObjectType:ETNormalObjectType]; 
} 

Yuck!這讓我厭惡。至少要有一種更清晰的閱讀方式,或者可能是一種統一的閱讀和寫作方式?

我使用的是Obj-C和Cocoa,但我不介意一些純粹的C函數。如果是唯一的方法,我甚至會使用預處理器的東西。

回答

17

我還沒有找到比複製字符串中的枚舉更好的方法。但是,我這樣做略有不同,即:

typedef enum { 
    kManipulateWindowTargetFrontWindow, 
    kManipulateWindowTargetNamedWindow, 
    kManipulateWindowTargetWindowNameContaining, 
    kManipulateWindowTargetDEFAULT = kManipulateWindowTargetFrontWindow, 
} ManipulateWindowTargetType; 
#define kManipulateWindowTargetTypeNamesArray @"FrontWindow", @"NamedWindow", @"WindowNameContaining", nil 

然後在執行:

static NSArray* kManipulateWindowTargetTypeArray = [[NSArray alloc] initWithObjects: kManipulateWindowTargetTypeNamesArray]; 

NSString* ManipulateWindowTargetTypeToString(ManipulateWindowTargetType mwtt) 
{ 
    return [kManipulateWindowTargetTypeArray objectAtIndex:mwtt]; 
} 

ManipulateWindowTargetType ManipulateWindowTargetTypeFromString(NSString* s) 
{ 
    NSUInteger n = [kManipulateWindowTargetTypeArray indexOfObject:s]; 
    check(n != NSNotFound); 
    if (n == NSNotFound) { 
     n = kManipulateWindowTargetDEFAULT; 
    } 
    return (ManipulateWindowTargetType) n; 
} 

我用的是#定義是避免聲明在頭文件中的數組的原因,但它會瘋狂地將枚舉的定義與字符串序列的定義分開,所以這是我找到的最好的折衷方案。

由於代碼是樣板文件,所以您實際上可以使它們成爲NSArray上的類別。

@interface NSArray (XMLExtensions) 

- (NSString*) stringWithEnum: (NSUInteger) e; 
- (NSUInteger) enumFromString: (NSString*) s default: (NSUInteger) def; 
- (NSUInteger) enumFromString: (NSString*) s; 

@end 

@implementation NSArray (XMLExtensions) 

- (NSString*) stringWithEnum: (NSUInteger) e; 
{ 
    return [self objectAtIndex:e]; 
} 

- (NSUInteger) enumFromString: (NSString*) s default: (NSUInteger) def; 
{ 
    NSUInteger n = [self indexOfObject:s]; 
    check(n != NSNotFound); 
    if (n == NSNotFound) { 
     n = def; 
    } 
    return n; 
} 

- (NSUInteger) enumFromString: (NSString*) s; 
{ 
    return [self enumFromString:s default:0]; 
} 


@end 

然後:

NSLog(@"s is %@", [kManipulateWindowTargetTypeArray stringWithEnum:kManipulateWindowTargetNamedWindow]); 
ManipulateWindowTargetType mwtt = (ManipulateWindowTargetType)[kManipulateWindowTargetTypeArray enumFromString:@"WindowNameContaining" default:kManipulateWindowTargetDEFAULT]; 
NSLog(@"e is %d", mwtt); 
+0

好主意保持頭文件中的枚舉和字符串序列。有些東西讓我困擾着將它們變成NSArray方法,但我可能會這樣做。謝謝! – andyvn22 2009-08-07 08:55:18

+0

定義的檢查功能在哪裏? – zekel 2010-05-18 15:30:09

+1

檢查在AssertMacros.h中定義,以及verify,require和變量_noerr,_action,_quiet,_string。他們應該經常撒在你的代碼中,這樣你才能在你的用戶之前找到你的錯誤。 – 2010-05-19 07:04:00

5

以下是我通常寫這些樣式的方法:

#define countof(array) (sizeof(array)/sizeof(array[0])) 

enum { 
    ETNormalObjectType, 
    ETRareObjectType, 
    ETEssentialObjectType 
}; 
typedef NSInteger ETObjectType; 

NSString *ETObjectTypesAsStrings[] = {[ETNormalObjectType] = @"ETNormalObjectType", 
             [ETRareObjectType] = @"ETRareObjectType", 
             [ETEssentialObjectType] = @"ETEssentialObjectType"}; 

NSString *ETStringFromObjectType(ETObjectType type) { 
    return ETObjectTypesAsStrings[type]; 
} 

ETObjectType ETObjectTypeFromString(NSString *string) { 
    NSString *match = nil; 
    for(NSInteger idx = 0; !match && (idx < countof(ETObjectTypesAsStrings)); idx += 1) { 
     if ([string isEqualToString:ETObjectTypesAsStrings[idx]]) { 
      match = ETObjectTypesAsStrings[idx]; 
     } 
    } 
    return match; 
} 

你最終不得不把你的枚舉值在兩個地方,原來的枚舉,而整數值映射到其字符串名稱數組。實際做映射的兩個函數雖然沒有映射的副本。

0

XML的偉大之處在於它可以轉換爲幾乎任何東西,甚至可以轉換爲代碼。翻譯一次只需要很多努力。我曾在幾個將XML轉換爲代碼的項目中工作。這節省了很多時間。例如,該技術在「XSLT Cookbook 2nd edition,S.Mangano,O'Reilley」一書的第12章中進行了介紹。

這不是一個簡單的解決方案,但如果你有一個很好的映射 - 具有高清(你的XML)的單點 - 可以生成.h文件用枚舉 - 可以生成表或函數來讀/寫xml中的值

這取決於枚舉的數量以及它們如果值得更改的頻率。 祝你好運!

5

我贊同Jon的解決方案,但你可以使用可怕的X-macro,以避免重複自己的。我不知道如何評論喬恩的代碼格式的答案,所以這裏是一個新的答案。

#define ETObjectTypeEntries \ 
ENTRY(ETNormalObjectType) \ 
ENTRY(ETRareObjectType) \ 
ENTRY(ETEssentialObjectType) 

typedef enum ETObjectType { 
#define ENTRY(objectType) objectType, 
    ETObjectTypeEntries 
#undef ENTRY 
} ETObjectType; 

NSString *ETObjectTypesAsStrings[] = { 
#define ENTRY(objectType) [objectType] = @"" # objectType, 
    ETObjectTypeEntries 
#undef ENTRY 
}; 

#define countof(array) (sizeof(array)/sizeof(array[0])) 

NSString *ETStringFromObjectType(ETObjectType type) { 
    return ETObjectTypesAsStrings[type]; 
} 

NSString *ETObjectTypeFromString(NSString *string) { 
    NSString *match = nil; 
    for(NSInteger idx = 0; !match && (idx < countof(ETObjectTypesAsStrings)); idx += 1) { 
     if ([string isEqualToString:ETObjectTypesAsStrings[idx]]) { 
      match = ETObjectTypesAsStrings[idx]; 
     } 
    } 
    return match; 
} 
+0

這真是噁心。 :D謝謝! (我打算使用NSArray策略中的類別,但玩起來真的很有趣。) – andyvn22 2009-08-11 01:43:40

+1

「真噁心」?我會說非常優雅。 – 2009-08-14 10:38:12

+0

@JonHess你變老了,那是一種恭維 – Madbreaks 2012-12-28 00:59:42

0

我用該溶液進行實驗 -

static NSString *stepTypeEnum[kStepTypeCount] = {@"one",@"two",@"three",@"four"}; 

int enumFromStrings(NSString*findString,NSString *strings[],int enumMax){ 
    for (int i=0;i<enumMax;i++){ 
     if ([findString isEqual: strings[i]]) { 
      return i; 
     } 
    } 
    NSLog(@"enum was not found for string %@", findString); 
    assert(false); 
    return INT_MAX; 
} 

我喜歡它,因爲它會檢查在編譯時串數組的長度,並且enumFromStrings功能是通用的,可重複使用的。你這樣稱呼它:

-(void)setType:(NSString*)typeString{ 
    type = enumFromStrings(typeString,stepTypeEnum,kStepTypeCount); 
}