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

前言

在我們編碼過程中,枚舉會經(jīng)常用到, 尤其是用來表示多種狀態(tài)時.
然而, 在OC中, 對枚舉進(jìn)行打印調(diào)試 或者 拼接方法 的操作的編程體驗(yàn)是非常差的.

例子

以下這種情況你應(yīng)該會經(jīng)常遇到:

// 你工作時的幾種狀態(tài)
typedef NS_ENUM(NSInteger, WorkStatus) {
    /** 摸魚*/
    WorkStatusUnKnown,
    /** 認(rèn)真工作*/
    WorkStatusWorking,
    /** 休息*/
    WorkStatusSleeping,
};

當(dāng)我們想要打印這個枚舉時, 默認(rèn)輸出的是這個枚舉標(biāo)識符所對應(yīng)的值, 這樣的效果是?非常不理想的, 只輸出數(shù)字,不直觀(我們之所以使用枚舉來定義狀態(tài), 不就是要直觀的表示嗎?), 為了達(dá)到直觀這一目的, 寫一個將?枚舉標(biāo)識符轉(zhuǎn)換成字符串的方法就勢在必得了:

- (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. 在某一個類的空間內(nèi)聲明定義轉(zhuǎn)換方法, 對于作用域外(其他類)的地方使用非常不便.
  2. 當(dāng)對枚舉的標(biāo)識符進(jìn)行增刪改操作時, 必須也要同時修改轉(zhuǎn)換方法內(nèi)的代碼, 非常不靈活.

優(yōu)化

優(yōu)化問題1

針對于 問題 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ù)聲明定義的錯誤. (使用NS_INLINE也可以.)
  2. __attribute__((unused)) 表示告訴編譯器忽略Unused Warning.

優(yōu)化問題2

解決 問題 2 的關(guān)鍵在于如何將一個枚舉標(biāo)識符靈活的轉(zhuǎn)換成字符串. 根據(jù)這個思路, 很自然的就可以聯(lián)想到 使用 宏定義中 # 可以將參數(shù)轉(zhuǎn)換成字符串的特性來解決.

// 定義枚舉標(biāo)識符和其對應(yīng)的值的宏
#define ENUM_VALUE(name,assign) name assign,

// ?將枚舉標(biāo)識符轉(zhuǎn)換成字符串的宏
#define ENUM_CASE(name,assign) case name: return @#name;

// 將字符串轉(zhuǎn)換為枚舉標(biāo)識符的宏
#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)將針對于 問題 1 優(yōu)化合并到上面這個代碼塊中.

使用

// 導(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)行手動換行):

// 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;
}

測試

    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

如果你有更好的想法 請不吝賜教.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容