iOS懶人開發(fā):自動去除字典空值對象,仿系統(tǒng)字典創(chuàng)建方法NSDictionaryOfVariableBindings

說明

模仿系統(tǒng)的快速生成字典的方法NSDictionaryOfVariableBindings并過濾掉值為nil的對象或內(nèi)容全為空格字符串欠动。

推薦適用場合:網(wǎng)絡(luò)請求生成參數(shù)字典徐块,無需判空绞铃。<BR>
其他創(chuàng)建字典的地方也可以使用师坎,注意此方法會過濾掉全為空格及@""字符串蟀悦,如不需要可自行修改沟于。

使用

    NSString *testStr = @"test";
    NSString *nilStr = nil;
    NSString *blankStr = @"   ";
    NSNumber *integerNumber = @124;
    NSNumber *NONumber = @(NO);
    NSNumber *zeroNumer = @0;
    People *peo = [[People alloc] init];
    People *peo_nil = nil;
    NSArray *array = @[];
    NSDictionary *dic = @{};
    
    NSDictionary *param = ZXDictionaryOfVariableBindings(testStr, nil, nilStr, blankStr, integerNumber, NONumber,zeroNumer, peo, peo_nil, array, dic);

param值:

{
    NONumber = 0;
    array =     (
    );
    dic =     {
    };
    integerNumber = 124;
    peo = "<People: 0x1c0452510>";
    testStr = test;
    zeroNumer = 0;
}

可以看到傳入的參數(shù)可為nil不會崩潰噪窘,且生成字典后自動去除了值為nil和全是空格的NSString

源碼

//.h
#define ZXDictionaryOfVariableBindings(...) [Tool _ZXDictionaryOfVariableBindings:@"" # __VA_ARGS__, __VA_ARGS__]

/**
 模仿系統(tǒng)的對象生成字典的宏定義:NSDictionaryOfVariableBindings(...)
 if v1 = @"something"; v2 = nil; v3 = @"something"; v4 = @"";
 ZXDictionaryOfVariableBindings(v1, v2, v3) is equivalent to [NSDictionary dictionaryWithObjectsAndKeys:v1, @"v1", v3, @"v3", nil];
 并且參數(shù)的值可為nil,@"", 會自動去除值為nil, @"", @"  "等的對象
 */
+ (NSDictionary *)_ZXDictionaryOfVariableBindings:(NSString *)firstArg, ...;

//.m
+ (NSDictionary *)_ZXDictionaryOfVariableBindings:(NSString *)firstArg, ... {
    firstArg = [firstArg stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSArray *keys = [firstArg componentsSeparatedByString:@","];
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:keys.count];
    va_list list;
    if (firstArg) {
        va_start(list, firstArg);
        id arg;
        for (NSString *key in keys) {
            arg = va_arg(list, id);
            if (!arg || [arg isKindOfClass:[NSNull class]]) {
                continue;
            }
            if ([arg isKindOfClass:[NSString class]]) {
                if ([[arg stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0) {
                    [dic setObject:arg forKey:key];
                }
            } else {
                [dic setObject:arg forKey:key];
            }
        }
        va_end(list);
    }
    return dic;
}

原理

廢話可不看↓

在開發(fā)經(jīng)常需要創(chuàng)建字典對象泞遗,但是創(chuàng)建字典時存入的對象值不能為nil衰猛,否則會崩潰。

尤其是在進(jìn)行網(wǎng)絡(luò)請求時刹孔,更是經(jīng)常需要對存入字典的對象判空,于是作為一個能少寫一行代碼絕不多寫一個字母的懶癌晚期患者,就想要是創(chuàng)建字典時能自動對傳入的對象判空并去除空值對象多好髓霞。

于是我就研究了系統(tǒng)的字典快捷創(chuàng)建方法NSDictionaryOfVariableBindings(...)卦睹,發(fā)現(xiàn)要解決此需求需要了解宏定義的使用,可變參數(shù)的使用方库。

宏定義

NSDictionaryOfVariableBindings初始化字典

創(chuàng)建字典的方法大家都比較熟悉结序,這里就不再說。

但是有一個根據(jù)對象名稱創(chuàng)建字典的方法很方便纵潦,這里要說一下:

#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)

這個方法是使用Autolayout時經(jīng)常使用的一個宏徐鹤,這個宏可以生成一個變量名到變量值映射的Dictionary。具體使用很簡單邀层,不再細(xì)說返敬,不知道的同學(xué)推薦你們可以使用此方法創(chuàng)建字典,很方便寥院。

使用此宏依舊需要對字典中的對象判空劲赠,防止傳入空值崩潰,要想自動去除值為nil的對象秸谢,要參數(shù)傳入之后入手凛澎,下面就來改造此宏定義自動去除傳入的空值。

宏定義中的參數(shù)含義

要想改造系統(tǒng)創(chuàng)建字典的方法估蹄,首先要知道系統(tǒng)創(chuàng)建字典的原理塑煎。

#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)中有3個參數(shù),下面先搞清楚這三個參數(shù)的含義,也就知道了該方法的原理臭蚁。

@"" # __VA_ARGS__中間#的作用:單個井號的作用是字符串化最铁,將后面的宏參數(shù) 用雙引號引起來,轉(zhuǎn)為一個C字符串刊棕。如:

define GET_NAME(X) #X
int a = 0; 
NSLog(@”%s”,GET_NAME(a)); //output: “a” 
NSLog(@”%s”,GET_NAME(a+3)); //output: “a+3” 
將會得到以下輸出:
a 
a+3 

可以看出#炭晒,將參數(shù)原樣轉(zhuǎn)換成字符串常量,如果參數(shù)是一個表達(dá)式甥角,那么輸出這個表達(dá)式的原樣字符串常量网严。

前面的@objc的編譯符號,不屬于宏操作的對象嗤无。如果有宏定義@#expression,出來后就是一個內(nèi)容是expression的內(nèi)容的NSString震束。

__VA_ARGS__表示的是宏定義中的...中的所有參數(shù)〉狈福可變參數(shù)將被統(tǒng)一處理垢村,在這里展開的時候編譯器會將__VA_ARGS__直接替換為輸入中的所有參數(shù)。

回頭再看看NSDictionaryOfVariableBindings的定義:

#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)

如果這樣生成兩個button的映射:

NSDictionaryOfVariableBindings(button1, button2); 

那么預(yù)編譯時就會轉(zhuǎn)換成:

_NSDictionaryOfVariableBindings(@"" "button1, button2", button1, button2, nil); 

由于兩個常量字符串放在一起就是字符串常量串聯(lián)嚎卫,將變成兩個字符串常量組合在一起的字符串常量嘉栓,也就是上面是一個空字符串@"""button1, button2"串聯(lián),所以上面的代碼等價于:

_NSDictionaryOfVariableBindings(@"button1, button2", button1, button2, nil); 

那么_NSDictionaryOfVariableBindings函數(shù)就可以將它的第一個參數(shù)按逗號,分割開作為key侵佃,后面就是各個key對應(yīng)的值了麻昼。因此這段代碼就創(chuàng)建了一個內(nèi)容為{ @"button1" = button1, @"button2" = button2 }Dictionary

可變參數(shù)

再回看宏定義NSDictionaryOfVariableBindings(...),其中...即可變參數(shù)馋辈,其實可變參數(shù)并不少見抚芦,比如:

// 日志輸出
NSLog(NSString *format, ...);
// NSString實例的創(chuàng)建
+(instancetype)stringWithFormat:(NSString *)format, ...;
// NSArray實例的創(chuàng)建
+(instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;

可變參數(shù)解析也很簡單,直接拿封裝的源碼舉例迈螟,注釋寫的很清楚了:

//.m
+ (NSDictionary *)_ZXDictionaryOfVariableBindings:(NSString *)firstArg, ... {
    // 取出第一個參數(shù)
    firstArg = [firstArg stringByReplacingOccurrencesOfString:@" " withString:@""];// 去除空格
    NSArray *keys = [firstArg componentsSeparatedByString:@","];
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:keys.count];
    // 定義一個指向個數(shù)可變的參數(shù)列表指針
    va_list list;
    if (firstArg) {
        // 初始化變量剛定義的va_list變量叉抡,這個宏的第二個參數(shù)是第一個可變參數(shù)的前一個參數(shù),是一個固定的參數(shù)
        va_start(list, firstArg);
        // 用于存放取出的參數(shù),C語言的字符指針, 指針根據(jù)offset來指向需要的參數(shù),從而讀取參數(shù)
        id arg;
        for (NSString *key in keys) {
            // 遍歷全部參數(shù) va_arg返回可變的參數(shù)(va_arg的第二個參數(shù)是你要返回的參數(shù)的類型)
            arg = va_arg(list, id);
            if (!arg || [arg isKindOfClass:[NSNull class]]) {
                continue;
            }
            if ([arg isKindOfClass:[NSString class]]) {
                if ([[arg stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0) {
                    [dic setObject:arg forKey:key];
                }
            } else {
                [dic setObject:arg forKey:key];
            }
        }
        // 清空參數(shù)列表答毫,并置參數(shù)指針args無效
        va_end(list);
    }
    return dic;
}

其中重點是不像其他字典初始化方法以nil作為傳參結(jié)束判斷的標(biāo)準(zhǔn)褥民。

  • nil作為傳參結(jié)束的變參方法:需要在定義方法時標(biāo)識NS_REQUIRES_NIL_TERMINATION,則初始化時未尾一定要加上nil烙常,如:
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;

因為這樣的方法中沒有提供對參數(shù)個數(shù)的檢測轴捎,需要判斷參數(shù)為nil時結(jié)束遍歷,銷毀指針偏移量蚕脏,否則會崩潰侦副。

  • 另外還有不以nil作為結(jié)束的變參方法,如NSLog
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
//注意后方的宏定義:NS_FORMAT_FUNCTION(1,2)驼鞭,我們點擊過去之后查看一下
#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))

看一下這句代碼

__attribute__((format(__NSString__,F, A)))

這句的意思是秦驯,參數(shù)的第F位是格式化字符串,從A位開始我們開始檢查

所以NSLog的第一個參數(shù)是一個格式化字符串挣棕,通過這個字條串就能獲得后面的參數(shù)個數(shù)译隘,而且能檢查參數(shù)數(shù)量錯誤。

所以本文創(chuàng)建字典的方法的重點就是用已知個數(shù)的可變參數(shù)洛心,去除為nil值的對象固耘。

參考鏈接

覺得好用的點個贊?~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市词身,隨后出現(xiàn)的幾起案子厅目,更是在濱河造成了極大的恐慌,老刑警劉巖法严,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损敷,死亡現(xiàn)場離奇詭異,居然都是意外死亡深啤,警方通過查閱死者的電腦和手機(jī)拗馒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溯街,“玉大人诱桂,你說我怎么就攤上這事洋丐。” “怎么了挥等?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵垫挨,是天一觀的道長。 經(jīng)常有香客問我触菜,道長,這世上最難降的妖魔是什么哀峻? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任涡相,我火速辦了婚禮,結(jié)果婚禮上剩蟀,老公的妹妹穿的比我還像新娘催蝗。我一直安慰自己,他們只是感情好育特,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布丙号。 她就那樣靜靜地躺著,像睡著了一般缰冤。 火紅的嫁衣襯著肌膚如雪犬缨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天棉浸,我揣著相機(jī)與錄音怀薛,去河邊找鬼。 笑死迷郑,一個胖子當(dāng)著我的面吹牛枝恋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗡害,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼焚碌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了霸妹?” 一聲冷哼從身側(cè)響起十电,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抑堡,沒想到半個月后摆出,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡首妖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年偎漫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有缆。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡象踊,死狀恐怖温亲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杯矩,我是刑警寧澤栈虚,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站史隆,受9級特大地震影響魂务,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泌射,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一粘姜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熔酷,春花似錦孤紧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至躺酒,卻和暖如春押蚤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阴颖。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工活喊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人量愧。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓钾菊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親偎肃。 傳聞我的和親對象是個殘疾皇子煞烫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355