前言
在我們編碼過程中,枚舉
會(huì)經(jīng)常用到, 尤其是用來表示多種狀態(tài)時(shí).
然而, 在OC中, 對(duì)枚舉
進(jìn)行打印調(diào)試 或者 拼接方法 的操作的編程體驗(yàn)是非常差的.
例子
以下這種情況你應(yīng)該會(huì)經(jīng)常遇到:
// 你工作時(shí)的幾種狀態(tài)
typedef NS_ENUM(NSInteger, WorkStatus) {
/** 摸魚*/
WorkStatusUnKnown,
/** 認(rèn)真工作*/
WorkStatusWorking,
/** 休息*/
WorkStatusSleeping,
};
當(dāng)我們想要打印這個(gè)枚舉時(shí), 默認(rèn)輸出的是這個(gè)枚舉標(biāo)識(shí)符所對(duì)應(yīng)的值, 這樣的效果是?非常不理想的, 只輸出數(shù)字,不直觀(我們之所以使用枚舉來定義狀態(tài), 不就是要直觀的表示嗎?), 為了達(dá)到直觀
這一目的, 寫一個(gè)將?枚舉標(biāo)識(shí)符轉(zhuǎn)換成字符串的方法就勢(shì)在必得了:
- (NSString *)WorkStatusDescription:(WorkStatus)status
{
NSString *desc = nil;
switch (status) {
case WorkStatusUnKnown:
desc = @"WorkStatusUnKnown";
break;
case WorkStatusWorking:
desc = @"WorkStatusWorking";
break;
case WorkStatusSleeping:
desc = @"WorkStatusSleeping";
break;
default:
desc = @"NoOne";
break;
}
return desc;
}
問題
這樣操作, 也許解決了不直觀的問題, 但是細(xì)看之下還是有兩點(diǎn)很大的問題.
- 在某一個(gè)類的空間內(nèi)聲明定義轉(zhuǎn)換方法, 對(duì)于作用域外(其他類)的地方使用非常不便.
- 當(dāng)對(duì)枚舉的標(biāo)識(shí)符進(jìn)行增刪改操作時(shí), 必須也要同時(shí)修改
轉(zhuǎn)換方法
內(nèi)的代碼, 非常不靈活.
優(yōu)化
優(yōu)化問題1
針對(duì)于 問題 1, 我們可以通過在頭文件中聲明定義函數(shù)來解決:
static NSString * WorkStatusDescription(WorkStatus status) __attribute__((unused));
static NSString * WorkStatusDescription(WorkStatus status) {
NSString *desc = nil;
switch (status) {
case WorkStatusUnKnown:
desc = @"WorkStatusUnKnown";
break;
case WorkStatusWorking:
desc = @"WorkStatusWorking";
break;
case WorkStatusSleeping:
desc = @"WorkStatusSleeping";
break;
default:
desc = @"NoOne";
break;
}
return desc;
}
有兩點(diǎn)需要解釋:
- 使用
static
可以防止發(fā)生函數(shù)重復(fù)聲明定義的錯(cuò)誤. (使用NS_INLINE
也可以.) -
__attribute__((unused))
表示告訴編譯器忽略Unused Warning
.
優(yōu)化問題2
解決 問題 2 的關(guān)鍵在于如何將一個(gè)枚舉標(biāo)識(shí)符靈活的轉(zhuǎn)換成字符串. 根據(jù)這個(gè)思路, 很自然的就可以聯(lián)想到 使用 宏定義中 #
可以將參數(shù)轉(zhuǎn)換成字符串的特性來解決.
// 定義枚舉標(biāo)識(shí)符和其對(duì)應(yīng)的值的宏
#define ENUM_VALUE(name,assign) name assign,
// ?將枚舉標(biāo)識(shí)符轉(zhuǎn)換成字符串的宏
#define ENUM_CASE(name,assign) case name: return @#name;
// 將字符串轉(zhuǎn)換為枚舉標(biāo)識(shí)符的宏
#define ENUM_STRCMP(name,assign) if ([string isEqualToString:@#name]) return name;
/// 聲明函數(shù) 及 定義枚舉
#define DECLARE_ENUM(EnumType,ENUM_DEF) \
typedef NS_ENUM(NSUInteger, EnumType) { \
ENUM_DEF(ENUM_VALUE) \
}; \
static NSString *stringFrom##EnumType(EnumType value) __attribute__((unused)); \
static EnumType EnumType##FromString(NSString *string) __attribute__((unused)); \
static NSString *stringFrom##EnumType(EnumType value) { \
switch(value) { \
ENUM_DEF(ENUM_CASE) \
default: return @""; \
} \
} \
\
static EnumType EnumType##FromString(NSString *string) { \
ENUM_DEF(ENUM_STRCMP) \
return (EnumType)0; \
}
為了一氣呵成, 已經(jīng)將針對(duì)于 問題 1
優(yōu)化合并到上面這個(gè)代碼塊中.
使用
// 導(dǎo)入定義宏所在的頭文件.
#import "enum_generator.h"
// 使用定義的宏聲明枚舉
#define WorkStatus(XX) \
XX(WorkStatusUnKnown,) \
XX(WorkStatusWorking,) \
XX(WorkStatusSleeping,=50)
// 生成定義的枚舉 與 轉(zhuǎn)換方法.
DECLARE_ENUM(WorkStatus,WorkStatus)
為了更直觀的感受, 我們進(jìn)入預(yù)編譯階段, 查看宏生成的代碼(為了看起來清晰 已經(jīng)進(jìn)行手動(dòng)換行):
// DECLARE_ENUM(WorkStatus,WorkStatus) 所生成的代碼
typedef enum WorkStatus : NSUInteger WorkStatus; enum WorkStatus : NSUInteger {
WorkStatusUnKnown ,
WorkStatusWorking ,
WorkStatusSleeping =50,
};
static NSString *stringFromWorkStatu(WorkStatus value) __attribute__((unused));
static WorkStatus WorkStatusFromString(NSString *string) __attribute__((unused));
static NSString *stringFromWorkStatus(WorkStatus value) {
switch(value) {
case WorkStatusUnKnown:
return @"WorkStatusUnKnown";
case WorkStatusWorking:
return @"WorkStatusWorking";
case WorkStatusSleeping:
return @"WorkStatusSleeping";
default:
return @"";
}
}
static WorkStatus WorkStatusFromString(NSString *string) {
if ([string isEqualToString:@"WorkStatusUnKnown"]) return WorkStatusUnKnown;
if ([string isEqualToString:@"WorkStatusWorking"]) return WorkStatusWorking;
if ([string isEqualToString:@"WorkStatusSleeping"]) return WorkStatusSleeping;
return (WorkStatus)0;
}
測(cè)試
WorkStatus testWorkStatus = WorkStatusUnKnown;
NSLog(@"workstatus is: %@", stringFromWorkStatus(testWorkStatus));
if (testWorkStatus == WorkStatusFromString(@"WorkStatusUnKnown")) {
NSLog(@"確認(rèn)在摸魚");
}
// 輸出:
// workstatus is: WorkStatusUnKnown
// 確認(rèn)在摸魚
More
Demo https://github.com/onekyle/EnumStringConvert/tree/master
如果你有更好的想法 請(qǐng)不吝賜教.