鄭重聲明:本文只是對編寫代碼過程中不合理的操作進(jìn)行吐槽,同時希望能夠?qū)⒆约浩綍r調(diào)試bug的思路進(jìn)行分享,不附帶對代碼作者以及任何程序猿(媛)的人身攻擊,請不要上綱上線。希望大家在閱讀完這篇文章后能夠以平常心對待從天而降的bug。(這其實(shí)是一篇技術(shù)博??)
至于文中bug的始作俑(勇)者,我依然認(rèn)為她是一個不可多得的合作伙伴。(誰還沒寫過幾個驚天大bug)
開始之前,請大家打開網(wǎng)易云,搜索涼涼,帶上耳機(jī),扶好坐穩(wěn)...

近期公司項(xiàng)目新增了一個大模塊,然而在測試的時候偶然發(fā)現(xiàn)老早以前的模塊某個xib文件約束報紅,出于職業(yè)操守我計劃順便將這個模塊進(jìn)行測試,結(jié)果粗大事兒咧,模塊中有一個界面的toolbar在我的瘋狂點(diǎn)擊下竟然紋絲不動。(手機(jī)鋼化膜都戳破了,應(yīng)該不是我力道不夠的問題)
excuse me?這個toolbar有點(diǎn)冷,難道是我不夠帥?不存在的,我讓我們后臺大帥比點(diǎn)了,也不行。??(請不要留言要聯(lián)系方式,人孩子都叫我叔叔了。)

根據(jù)我多年的經(jīng)驗(yàn),如果這個toolbar一直是這樣它不可能上線。(嚴(yán)肅臉)
想到這里我決定先給自己泡一杯菊花茶,可惜沒有枸杞有點(diǎn)小遺憾。
作為一名合格的程序員,還是要勇于背鍋的,也許是我某一天一不小心動了某行代碼導(dǎo)致這里出問題了。
嗯,有道理,先回退版本build一下。
然而事實(shí)證明并沒有什么卵用。那還等什么,甩鍋?。。?!
望著手里的 iphoneXXX plus,我不經(jīng)陷入了沉思.
它究竟經(jīng)歷了什么?
那是一個天氣晴朗,萬里無云,天空中飄著蒙蒙細(xì)雨的深夜,那一天我再次收到了系統(tǒng)版本升級通知,依稀記得那天沒有枸杞,也沒有菊花茶,有點(diǎn)微微發(fā)抖的手錯誤的按下了立即更新...
二十分鐘后,望著系統(tǒng)煥然一新的手機(jī),我又一次陷入了沉思... 唉,還是把Xcode也升級了吧。
哦!我知道了,一定是系統(tǒng)版本的原因,不是bug。找了舊版本的測試機(jī)build,看著活蹦亂跳的toolbar我的內(nèi)心是崩潰的。

代碼如下:
self.toobar = [[CSSMyCustomDetailToobar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
[self.toobar toobarWithItems:itemArray[0]];
問題可能出在 CSSMyCustomDetailToobar :
@interface CSSMyCustomDetailToobar : UIToolbar
@property (nonatomic,assign) id <CSSMyCustomDetailToobarDelegate > delegateToobar;
- (void)toobarWithItems:(NSArray *)items;
@end
再看toobarWithItems方法:
- (void)toobarWithItems:(NSArray *)items
{
[items enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake((self.bounds.size.width/items.count)*idx, 0, self.bounds.size.width/items.count, self.bounds.size.height)];
btn.tag = idx+10;
if ([CSSUserInfoManager manager].isHiddenSwing) {
btn.tag = btn.tag + 1;
}
[btn addTarget:self action:@selector(operationAction:) forControlEvents:UIControlEventTouchUpInside];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:obj[@"image"]]];
imageView.centerX = btn.width/2;
imageView.y = btn.frame.origin.y+5;
UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, [imageView getFrame_Bottom], btn.width, btn.height- [imageView getFrame_Bottom])];
titleLabel.text = obj[@"title"];
[btn addSubview:imageView];
[btn addSubview:titleLabel];
titleLabel.font = [UIFont systemFontOfSize:12];
titleLabel.textColor = [UIColor see_colorWithHex:0x666666];
titleLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:btn]; //?????? why?
}];
self.backgroundColor = [UIColor whiteColor];
}
以上代碼 除了 //?????? why? ,其他的都是原汁原味。
讓我們來解析一下這段代碼,借此琢磨一下作者當(dāng)時的心路歷程。
解析中
.
..
...
....
.....
......
.......
........
.........
..........
...........
............
解析失?。。?!
是否強(qiáng)制解析,此操作可能會造成無法挽回的后果。 (y / n)
y
??
從上面的代碼來看,這里應(yīng)該是想要把button添加在toolbar上面,這個是沒毛病的。
but...
wait, wait, wait,等一下...
[self addSubview:btn]; ???
視圖層次結(jié)構(gòu)走起來。

怪不得點(diǎn)不動,按鈕上面蓋四層視圖是什么鬼?
切回舊版本系統(tǒng)看一下

縱觀不同系統(tǒng)下層次結(jié)構(gòu),不難發(fā)現(xiàn)兩個系統(tǒng)版本下調(diào)用UIToolbar的addSubview:方法視圖添加的位置是不同的。
iOS10.0下按鈕被添加在_UIVisualEffectFilterView上層,處于所有子視圖之上,zIndex最大。
iOS11下UIToolbar多了_UIToolbarContentView和_UIButtonBarStackView兩層視圖并且這兩層視圖是在_UIVisualEffectSubview之上的,而我們的按鈕就被添加在_UIVisualEffectSubview上層,因此我們添加的按鈕就被_UIToolbarContentView和_UIButtonBarStackView覆蓋了接收不到點(diǎn)擊事件。
嗯,終于找到了原因看來能夠早點(diǎn)下班回家了。
重新修改代碼,使用按鈕創(chuàng)建UIBarButtonItem并添加進(jìn)toolbar,千萬別問我UIBarButtonItem怎么添加到toolbar。
迫不及待的build一下,fuck,竟然還是不能點(diǎn)。
感覺我的智商受到了慘無人道的侮辱。
再看看視圖層次結(jié)構(gòu):

竟然少了兩層,不錯不錯,還是取得了一點(diǎn)點(diǎn)成就的。
我們發(fā)現(xiàn),修改之前按鈕上面 _UIToolbarContentView和_UIButtonBarStackView 各有兩層,現(xiàn)在只剩一層了,少的那一層去哪里了呢?
我們在圖中找找線索:

由此猜測,可能這一坨視圖是由兩個toolbar合成的。(為我自己的機(jī)智點(diǎn)個贊??)
其中一個toolbar被另一個toolbar使用addSubview方法添加進(jìn)自己的視圖。
通過不懈的努力,在控制器中發(fā)現(xiàn)了以下代碼:
[self.navigationController.toolbar addSubview:self.toobar];
self.navigationController.toolbarHidden = NO;

@¥#%@……#%……@#&*¥#……
咳咳... 不好意思,語速太快岔氣了。
進(jìn)過一番苦戰(zhàn),toolbar終于正常工作,你以為就能下班了?
too young too naive!
不知各位之前有沒有注意到下面這幾行代碼:
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake((self.bounds.size.width/items.count)*idx, 0, self.bounds.size.width/items.count, self.bounds.size.height)];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:obj[@"image"]]];
imageView.centerX = btn.width/2;
imageView.y = btn.frame.origin.y+5;
UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, [imageView getFrame_Bottom], btn.width, btn.height- [imageView getFrame_Bottom])];
titleLabel.text = obj[@"title"];
[btn addSubview:imageView];
[btn addSubview:titleLabel];
titleLabel.font = [UIFont systemFontOfSize:12];
titleLabel.textColor = [UIColor see_colorWithHex:0x666666];
titleLabel.textAlignment = NSTextAlignmentCenter;
說到這幾行代碼那可就牛逼了,又是加減又是乘除的,一看就是出自文化人之手。
雖然這幾行代碼運(yùn)行出來的結(jié)果是沒問題的,但是怎么就看著這么奇怪呢,這里是通過給button添加了一個UIImageView和一個UILabel然后進(jìn)行了一系列運(yùn)算計算frame來實(shí)現(xiàn)文字和圖片的折行顯示(圖文混排),但是這種方法看起來好像有那么一點(diǎn)點(diǎn)不優(yōu)雅。
其實(shí)這里可以采用屬性字符串來達(dá)到同樣的效果,代碼如下:
+ (instancetype)see_attributedStringWithImage:(UIImage *)image imageSize:(CGSize)size title:(NSString *)title titleColor:(UIColor *)color fontSize:(CGFloat)fontSize lineSpace:(CGFloat)space {
//創(chuàng)建文本附件
NSTextAttachment * atta = [[NSTextAttachment alloc]init];
//設(shè)置圖片
atta.image = image;
//設(shè)置圖片大小
atta.bounds = CGRectMake(0, 0, size.width, size.height);
NSAttributedString * att = [NSAttributedString attributedStringWithAttachment:atta];
//追加空行
NSMutableAttributedString * attM = [[NSMutableAttributedString alloc]initWithAttributedString:att];
NSAttributedString * str = [[NSAttributedString alloc]initWithString:@"\n " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:space]}];
[attM appendAttributedString:str];
//追加文字
NSAttributedString * titles = [[NSAttributedString alloc]initWithString:[NSString stringWithFormat:@"\n%@",title] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize],NSForegroundColorAttributeName:color}];
[attM appendAttributedString:titles];
return attM.copy;
}
這樣可以省去很多不必要的數(shù)學(xué)運(yùn)算。
至此本期吐槽結(jié)束。
至于這段代碼出自何人之手并不重要,(誰還沒有年輕過,畢竟大家都是從菜雞一步步過來的。)重要的是目前線上App在iOS11.4版本的設(shè)備上是癱瘓的... 我的內(nèi)心受到了極大的傷害(疼痛到無法夫吸),不說了改胤禩(八阿哥)去。

續(xù)
(以下情節(jié)純屬虛構(gòu),如有雷同純屬巧合,請隨意入座。)
一年前:

NSLog(@"h");
NSLog(@"e");
NSLog(@"l");
NSLog(@"l");
NSLog(@"o");
NSLog(@" ");
NSLog(@"w");
NSLog(@"o");
NSLog(@"r");
NSLog(@"l");
NSLog(@"d");
唉呀媽呀,終于寫完了。

嗯,不錯,我這段代碼老牛逼了。后面來的人看到了我這段代碼一定會對我頂禮膜拜。
要不然署個名留個聯(lián)系方式?
算了算了,做人要低調(diào),低調(diào),低調(diào)!
一年后:

嗯? 這里好像有一個bug。

嗯... 這個bug值得好好研究一下。

咦?這里為什么要這樣寫呢?

媽的,這sb代碼誰寫的。@#¥¥&¥#(@#()@??