[iOS開發(fā)必備]一個優(yōu)雅的打印框架:字典以JSON格式打印

緣起

我們在跟后端對接調試接口的時候,會將返回數(shù)據轉成字典后打印出來垢乙。這時候我們發(fā)現(xiàn),Xcode控制臺輸出的格式并非JSON格式酪刀,跟后端同事溝通協(xié)作的時候不是特別方便羊壹。特別要吐槽的是打印出來的中文是Unicode編碼齐婴,這也太反人性了。于是我寫了一個框架情妖,完美解決以上痛點诱担。
比如后端下發(fā)了這樣的JSON數(shù)據:

{
    "address": "我是云南的,云南麗江的",
    "info": {
        "blog": "http://www.reibang.com/u/399cc7c53fad",
        "isSingle": true,
        "nickName": "小而白",
        "score": 0.3
    },
    "name": "大魔王"
}

實際上蔫仙,我們是以NSData類型(Objective-C)去接收網絡數(shù)據的。上述JSON字符串對應的NSData恤煞,可通過如下方法轉換:

    NSString *jsonStr = @"{\
    \"address\": \"我是云南的施籍,云南麗江的\",\
    \"info\": {\
        \"blog\": \"http://www.reibang.com/u/399cc7c53fad\",\
        \"isSingle\": true,\
        \"nickName\": \"小而白\",\
        \"score\": 0.3\
    },\
    \"name\": \"大魔王\"\
    }";
    NSData *jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

此時我們在本地模擬出了接收到的NSData數(shù)據,將jsonData轉化成字典:

NSError *serializationError = nil;
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&serializationError];
//(AFNetWorking框架也是使用到這個方法)

debug調試responseObject信息截圖如下:


responseObject內存信息.png

直接手寫構造上面的字典:

NSDictionary *dict = @{
        @"name":@"大魔王",
        @"address":@"我是云南的喜喂,云南麗江的",
        @"info": @{
            @"nickName":@"小而白",
            @"blog":@"http://www.reibang.com/u/399cc7c53fad",
            @"score":@(0.3),
            @"isSingle":@(YES)
        }
    };
NSLog(@"字典:%@",dict);

Xcode控制臺上打印顯示:


默認情況下打印字典.png

默認的打印格式除了中文亂碼以外玉吁,還有兩個不容忽視的問題:
1腻异、字典中@"isSingle":@(YES) BOOL類型的值被輸出為1
2、字典中@"score":@(0.3) 浮點數(shù)0.3被加上了引號變成了字符格式

解決方案

為了解決以上痛點捂掰,我查閱了相關資料曾沈,寫了一個輕量級的零侵入打印框架 SZJsonLog

使用該框架后打印效果是這樣的


SZJsonLog打印字典.png

完美還原原始JSON數(shù)據塞俱。我已經將該框架上傳到Github吏垮,您可以點擊 SZJsonLog源碼 下載,文件直接拖入工程膳汪,使用系統(tǒng)打印方法即可。祝您享用愉快粘我!

如何實現(xiàn)痹换?

其實很簡單,一句話就能說明白:依次取出字典中的鍵值對娇豫,進行字符串拼接。最終輸出JSON格式的字符串氮昧。
NSLog打印字典(NSDictionary)和數(shù)組(NSArray)的時候會走- (NSString *)descriptionWithLocale:(id)locale來決定打印的字符串浦楣。所以現(xiàn)在我們在分類中重寫NSDictionary和NSArray(兩者可以相互嵌套)的- (NSString *)descriptionWithLocale:(id)locale方法來獲得我們預期的結果。
在使用po命令調試的時候椒振,會走- (NSString *)debugDescription方法,我們同樣覆蓋該方法來實現(xiàn)預期效果庐杨。
至于零侵入夹供,你們應該想到了,就是利用runtime的方法交換哮洽,在編譯時注冊經過改造的打印方法。
以NSDictionary示例氛什,貼出部分代碼

@implementation NSDictionary (SZJsonLog)

- (NSString *)szlog_descriptionWithLocale:(id)locale {
    return [self descriptionWithLocale:locale indent:0];
}

- (NSString *)szlog_descriptionWithLocale:(id)locale indent:(NSUInteger)level {
    NSMutableString *desc = [NSMutableString string];
    NSMutableString *tabString = [[NSMutableString alloc] initWithCapacity:level];
    for (NSUInteger i = 0; i < level; ++i) {
        [tabString appendString:@"\t"];
    }
    NSString *tab = @"";
    if (level > 0) {
        tab = tabString;
    }
    [desc appendString:@"{\n"];
    // 對字典排序
    NSArray *allkeys = [self.allKeys sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        return [obj1 compare:obj2];
    }];
    
    for (id k in allkeys) {
        id obj = [self objectForKey:k];
        NSString *key = k;
        if ([key isKindOfClass:[NSString class]]) {
            key = [NSString stringWithFormat:@"\"%@\"", key];
        }
        if ([obj isKindOfClass:[NSString class]]) {
            [desc appendFormat:@"%@\t%@: \"%@\",\n", tab, key, obj];
        } else if ([NSStringFromClass([obj class]) isEqualToString:@"__NSCFBoolean"]) {
            [desc appendFormat:@"%@\t%@: %s,\n", tab, key, [(NSNumber *)obj boolValue] ?"true": "false"];
        } else if ([obj isKindOfClass:[NSArray class]]
                   || [obj isKindOfClass:[NSDictionary class]]) {
            [desc appendFormat:@"%@\t%@: %@,\n", tab, key, [obj descriptionWithLocale:locale indent:level + 1]];
        } else if ([obj isKindOfClass:[NSData class]]) {
            // 如果是NSData類型枪眉,嘗試去解析結果,以打印出可閱讀的數(shù)據
            sz_convertToJsonString(obj, level, desc, tab, key);
        } else if ([obj isKindOfClass:[NSNull class]])  {
            [desc appendFormat:@"%@\t%@: null,\n", tab, key];
        } else {
            [desc appendFormat:@"%@\t%@: %@,\n", tab, key, obj];
        }
    }
    // 查出最后一個,的范圍
    NSRange range = [desc rangeOfString:@"," options:NSBackwardsSearch];
    if (range.length) {
        // 刪掉最后一個,
        [desc deleteCharactersInRange:range];
    }
    [desc appendFormat:@"%@}", tab];
    return desc;
}

- (NSString *)szlog_debugDescription {
    return [self descriptionWithLocale:nil indent:0];
}

+ (void)load {
    SZFUNCTIONSWAPREGISTER//方法交換
}

至于NSArray部分堡纬,無非字符串的拼接格式不同而已蒿秦,就不贅述。

Swift如何使用棍鳖?

很簡單,拖入工程后悴灵,只需將swift中的Dictionary轉換成NSDictionary來用即可骂蓖。舉個??

var dict: [String : Any]  = [
            "key1" : true,
            "key2" : 0.3,
            "key3" : ["key1" : ["1",2,"中文","http://www.baidu.com"],
                      "key2": "value2"],
            
        ]
 print(dict as NSDictionary)

輸出截圖如下:


swift中的字典打印.png

好的川尖,故事寫到這就結束了,謝謝您的拜讀叮喳!音響老師片尾曲請放起來。
慢畔濒!請留步锣咒,還有彩蛋,哈哈哈毅整。
或許你們有疑惑,開頭講到json字符串可以轉換成字典艇潭,調用系統(tǒng)現(xiàn)成方法就行。反過來蹋凝,字典轉成json字符串,難道就沒有相應的系統(tǒng)方法了房交?用得著大費周章這么解析拼接嗎伐割?的確是有的!我們這就試下

NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted  error:&error];//這里的dict仍是前面用到的字典用例
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"系統(tǒng)默認打印格式打印jsonString:%@",jsonString);

控制臺輸出


字典轉json.png

有個很大的問題:0.3的精度丟失了白群。此外硬霍,網址加上了轉義的斜杠“\”。所以這個方案我是不能接受的唯卖。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末拜轨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子橄碾,更是在濱河造成了極大的恐慌,老刑警劉巖法牲,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拒垃,死亡現(xiàn)場離奇詭異,居然都是意外死亡悼瓮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門副硅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翅萤,“玉大人腊满,你說我怎么就攤上這事培己。” “怎么了省咨?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵零蓉,是天一觀的道長。 經常有香客問我敌蜂,道長,這世上最難降的妖魔是什么汗贫? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任秸脱,我火速辦了婚禮,結果婚禮上摊唇,老公的妹妹穿的比我還像新娘。我一直安慰自己嘹害,他們只是感情好吮便,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布幢踏。 她就那樣靜靜地躺著,像睡著了一般僚匆。 火紅的嫁衣襯著肌膚如雪搭幻。 梳的紋絲不亂的頭發(fā)上咧擂,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天松申,我揣著相機與錄音,去河邊找鬼贸桶。 笑死,一個胖子當著我的面吹牛琉历,可吹牛的內容都是我干的水醋。 我是一名探鬼主播旗笔,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼换团,長吁一口氣:“原來是場噩夢啊……” “哼宫蛆!你這毒婦竟也來了?” 一聲冷哼從身側響起耀盗,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤叛拷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忿薇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡揉燃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年筋栋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弊攘。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡襟交,死狀恐怖,靈堂內的尸體忽然破棺而出捣域,到底是詐尸還是另有隱情醋界,我是刑警寧澤提完,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站逐样,受9級特大地震影響打肝,放射性物質發(fā)生泄漏脂新。R本人自食惡果不足惜粗梭,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滞乙。 院中可真熱鬧鉴嗤,春花似錦、人聲如沸醉锅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽经柴。三九已至,卻和暖如春口锭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹃操。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工荆隘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椰拒。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像燃观,于是被迫代替她去往敵國和親褒脯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容