利用宏定義實(shí)現(xiàn)枚舉轉(zhuǎn)字符串

前言

在我們編碼過程中,枚舉會(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)很大的問題.

  1. 在某一個(gè)類的空間內(nèi)聲明定義轉(zhuǎn)換方法, 對(duì)于作用域外(其他類)的地方使用非常不便.
  2. 當(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)需要解釋:

  1. 使用static可以防止發(fā)生函數(shù)重復(fù)聲明定義的錯(cuò)誤. (使用NS_INLINE也可以.)
  2. __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

靈感來自 https://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in-c/202511#202511

Demo https://github.com/onekyle/EnumStringConvert/tree/master

如果你有更好的想法 請(qǐng)不吝賜教.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跃惫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子曾掂,更是在濱河造成了極大的恐慌土全,老刑警劉巖硕勿,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迹炼,死亡現(xiàn)場(chǎng)離奇詭異仔燕,居然都是意外死亡舟误,警方通過查閱死者的電腦和手機(jī)葡秒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嵌溢,“玉大人眯牧,你說我怎么就攤上這事±挡荩” “怎么了学少?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秧骑。 經(jīng)常有香客問我版确,道長,這世上最難降的妖魔是什么乎折? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任绒疗,我火速辦了婚禮,結(jié)果婚禮上骂澄,老公的妹妹穿的比我還像新娘吓蘑。我一直安慰自己,他們只是感情好坟冲,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布士修。 她就那樣靜靜地躺著,像睡著了一般樱衷。 火紅的嫁衣襯著肌膚如雪棋嘲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天矩桂,我揣著相機(jī)與錄音沸移,去河邊找鬼。 笑死侄榴,一個(gè)胖子當(dāng)著我的面吹牛雹锣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播癞蚕,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蕊爵,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了桦山?” 一聲冷哼從身側(cè)響起攒射,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤醋旦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后会放,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饲齐,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年咧最,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捂人。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡矢沿,死狀恐怖滥搭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捣鲸,我是刑警寧澤论熙,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站摄狱,受9級(jí)特大地震影響脓诡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜媒役,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一祝谚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酣衷,春花似錦交惯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至啊片,卻和暖如春只锻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背紫谷。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工齐饮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人笤昨。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓祖驱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瞒窒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捺僻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器匕坯,智...
    卡卡羅2017閱讀 134,704評(píng)論 18 139
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,238評(píng)論 0 4
  • · 事情經(jīng)過 昨天傍晚因?yàn)榕畠涸趯W(xué)校的事情而惱火醒颖,情緒一度跌到谷底妻怎。一半惱的是女兒的情商壳炎,一半惱的是告狀的家長那一...
    玄月之佑閱讀 1,074評(píng)論 5 4
  • 這個(gè)月開始讀《硅谷鋼鐵俠》泞歉,書讀到一半,就開始走神了匿辩。因?yàn)轳R斯克的前妻賈斯汀觸動(dòng)了我腰耙,她和馬斯克有良好的感情基礎(chǔ),...
    熊熊如焰閱讀 414評(píng)論 0 1
  • 我常巢颍幻想自己在一個(gè)夕陽西下的海邊愜意享受自然的美景挺庞,或者在一個(gè)山清水秀的桃花源呼吸新鮮空氣,或者在奔馳的列車上聆...
    可可咳咳閱讀 269評(píng)論 0 0