一個(gè)未能重現(xiàn) Bug 的修復(fù)過(guò)程(未完)

一個(gè)線上bug ,一直沒(méi)法重現(xiàn)悠就,但是崩潰率不低,這就問(wèn)題了有點(diǎn)頭疼啦

bug 的堆棧信息

上述就是具體的崩潰信息充易,原本以為定位這么仔細(xì)就可以立馬找出原因梗脾,然而并沒(méi)有。
這邊用了 DZNEmptyDataSetCHTCollectionViewWaterfallLayout 盹靴,崩潰的點(diǎn)也是在此處出現(xiàn)的炸茧。瑞妇。。

目前沒(méi)法重現(xiàn)這一個(gè) Bug梭冠, 只能通過(guò)圖中返回的情況辕狰,定位到代碼中:

- (CGSize)collectionViewContentSize {
  NSInteger numberOfSections = [self.collectionView numberOfSections];
  if (numberOfSections == 0) {
    return CGSizeZero;
  }
  CGSize contentSize = self.collectionView.bounds.size;
  contentSize.height = [self.columnHeights[0] floatValue];
  return contentSize;
}

- (BOOL)dzn_canDisplay {
    if (self.emptyDataSetSource && [self.emptyDataSetSource conformsToProtocol:@protocol(DZNEmptyDataSetSource)]) {
        if ([self isKindOfClass:[UITableView class]] || [self isKindOfClass:[UICollectionView class]] || [self isKindOfClass:[UIScrollView class]]) {
            return YES;
        }
    }
    return NO;
}

可以確定是 崩在 dzn_canDisplay 這里,但是嘗試好多遍都不知道問(wèn)題在哪里...

一控漠、 猜

猜測(cè)蔓倍,是否調(diào)用 [self.collectionView numberOfSections] 的時(shí)候, self.collectionView 的時(shí)候已經(jīng)被提前釋放或者說(shuō)已經(jīng)被干掉啦盐捷。

首先可以肯定的是偶翅,當(dāng) self.collectionView 被干掉此處肯定會(huì)崩,但是此種情況基本不存在碉渡,在 CHTCollectionViewWaterfallLayout 中它是不可被修改的聚谁,而外部的collectionView 又是在生命周期中,不會(huì)被干掉滞诺,所以此處排除垦巴。。铭段。
另外骤宣,如果是 self.collectionView 的問(wèn)題,那么 上述圖中只會(huì)截止崩在該位置序愚,不會(huì)繼續(xù)走 dzn_canDisplay等方法憔披。

二、理一下常見(jiàn)的 Carsh

再判斷爸吮,可以肯定的是什么造成啦 collectionViewContentSizedzn_canDisplay方法有問(wèn)題芬膝,而又沒(méi)有頭緒...

回過(guò)頭來(lái),先看看分析iOS Crash文件:符號(hào)化iOS Crash文件的3種方法形娇,需要使用Xcode符號(hào)化 crash log锰霜,我們需要下面所列的3個(gè)文件:

  1. crash報(bào)告(.crash文件)
  2. 符號(hào)文件 (.dsymb文件)
  3. 應(yīng)用程序文件 (appName.app文件,把IPA文件后綴改為zip桐早,然后解壓癣缅,Payload目錄下的appName.app文件), 這里的appName是我們的應(yīng)用程序的名稱。

現(xiàn)在關(guān)鍵問(wèn)題哄酝,這bug 根本一直不能在重現(xiàn)友存,可以單純的看到堆棧信息的崩潰日志,再想想一般是什么原因會(huì)造成崩潰陶衅,回顧下 常見(jiàn)的Crash類型:

  • 2-1屡立、看門狗

看門狗也就是 Watchdog 機(jī)制,它是iOS為了保持用戶界面的響應(yīng)引入的一種機(jī)制搀军, 膨俐。如果我們的應(yīng)用未能及時(shí)的響應(yīng)一些用戶界面事件勇皇,如啟動(dòng)、暫停焚刺、恢復(fù)和終止敛摘,Watchdog就會(huì)殺死程序并生成一個(gè)Watchdog超時(shí)崩潰報(bào)告。Watchdog超時(shí)時(shí)間并沒(méi)有明文規(guī)定檩坚,但通常會(huì)少于網(wǎng)絡(luò)超時(shí)。(5秒不一定正確)

場(chǎng)景:

  • 主線程執(zhí)行同步的網(wǎng)絡(luò)請(qǐng)求诅福,而且請(qǐng)求時(shí)間特別長(zhǎng)匾委。
  • 主線程死鎖。
  • 長(zhǎng)時(shí)間讀寫(xiě)本地文件
    ...
// 放在 AppDelegate didFinishLaunchingWithOptions
dispatch_sync(dispatch_get_main_queue(), ^{
     NSLog(@"永遠(yuǎn)不會(huì)調(diào)用");
});
NSLog(@"永遠(yuǎn)不會(huì) run");
崩了
  • 2-2氓润、用戶強(qiáng)制退出

類似強(qiáng)制關(guān)機(jī)的情況赂乐。

  • 2-3、內(nèi)存不夠

在我們App運(yùn)行的過(guò)程中咖气,系統(tǒng)內(nèi)存緊張時(shí)通常會(huì)先發(fā)警告挨措,同時(shí)把后臺(tái)掛起的程序終止掉,最終如果還是內(nèi)存不夠的話就會(huì)終止掉當(dāng)前前臺(tái)的進(jìn)程崩溪。
也提醒我們要及時(shí)的殺掉不用的內(nèi)存浅役,否則內(nèi)存占用越來(lái)越高,一旦超過(guò)系統(tǒng)限制就會(huì)被系統(tǒng)殺死伶唯,然后就Carsh 啦觉既。

  • 2-4、自己產(chǎn)生的 bug

最常見(jiàn)的數(shù)組越界乳幸,或者其他五花八門的瞪讼,反正就是自己產(chǎn)生的問(wèn)題,像上述遇到的問(wèn)題粹断。符欠。。

來(lái)自 常見(jiàn)的Crash類型瓶埋。

此處提醒希柿,去看看 DZNEmptyDataSet 和 CHTCollectionViewWaterfallLayout 中的 issues, 是不是里面的問(wèn)題养筒,到它們的 github 上的 issues 轉(zhuǎn)了一大圈狡汉,也沒(méi)有類似的問(wèn)題...

三、盡量讓其重現(xiàn)

線上的崩潰率不低闽颇,但是為什么我們自己測(cè)試不出來(lái)啦盾戴,暫時(shí)還是只能去分析具體崩潰的位置, 在又一次認(rèn)真的看堆棧崩潰信息發(fā)現(xiàn), crash 在 objc_msgSend()兵多,而發(fā)生這種情況的原因可能是:

  • 向一個(gè)已經(jīng)釋放的對(duì)象發(fā)送消息尖啡,野指針之類的
  • 接收者的內(nèi)存錯(cuò)誤橄仆。

反正就是接收者的問(wèn)題,而我上面圖中的那就是 self.emptyDataSetSource 啦衅斩,此時(shí)在想難道是它被提前釋放掉了盆顾,但是下面這個(gè) view ,無(wú)論如何都是在是會(huì)返回的啊

- (UIView *)customViewForEmptyDataSet:(UIScrollView *)scrollView 

而且對(duì)于 CollectionView 或者 viewModel 都是強(qiáng)引用啊,在生命周期內(nèi)不會(huì)自己釋放掉啊畏梆。

PS一個(gè)點(diǎn):編譯優(yōu)化會(huì)使調(diào)用堆棧中指向第二段的調(diào)用點(diǎn)(call site)可能并不是真正導(dǎo)致崩潰的調(diào)用您宪。

此時(shí)突然想到了我們的崩潰軌跡,有著大量的 KVO痕跡

1奠涌、1秒前 DiscoveryViewController viewDidAppear:(,)
2宪巨、1秒前 HomeViewController viewDidAppear:(,)
3、2秒前 NSKVONotifying_UICollectionView handlePan:(UIScrollViewPanGestureRecognizer,)
4溜畅、2秒前 NSKVONotifying_UICollectionView handlePan:(UIScrollViewPanGestureRecognizer,)

是否和 KVO 有關(guān)捏卓??慈格?然而此處是沒(méi)有用 KVO的啊怠晴,而且用了地方都是處理過(guò)的,此時(shí)我們只能先再了解下KVO一個(gè)點(diǎn):

  • NSKVONotifying_UICollectionView 的由來(lái)
    當(dāng)某個(gè)類的實(shí)例對(duì)象的key第一次被觀察時(shí)浴捆,系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類NSKVONotifying_類名蒜田,在這個(gè)派生類中重寫(xiě)該類中被觀察的屬性的 setter 方法。
@property(nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer NS_AVAILABLE_IOS(5_0);
@property(nonatomic) CGPoint contentOffset;  

在添加KVO觀察后选泻,我們?cè)?ObserveValueForKeyPath 打上斷點(diǎn)物邑,看一下Object 。

在ObserveValueForKeyPath 時(shí)方法的Object 的顯示

此時(shí)isa指針被系統(tǒng)動(dòng)態(tài)的指向了派生類NSKVONotifying_UICollectionView
注意:KVO的本質(zhì)就是監(jiān)聽(tīng)對(duì)象的屬性進(jìn)行賦值的時(shí)候有沒(méi)有調(diào)用setter方法滔金。

本頁(yè)面沒(méi)有用到色解,那只能再次猜測(cè):是不是其他頁(yè)面(有用到空頁(yè)面,瀑布流)返回過(guò)來(lái)的餐茵,并且用來(lái)了KVO 而沒(méi)提前釋放 —— 一般是沒(méi)有的科阎,臨走前就算沒(méi)有釋放,也不會(huì)調(diào)用dzn_canDisplay 方法的忿族。

所以锣笨,此處穩(wěn)妥一點(diǎn)讓Bug重現(xiàn)的方法就是 找到一個(gè)操作,會(huì)涉及方法
- (BOOL)dzn_canDisplay,
- (CGSize)collectionViewContentSize
而且又歷經(jīng) HomeViewController道批,DiscoveryViewController错英,暫時(shí)符合該系列行為的就是:

  • 啟動(dòng) app 的操作。

KVO 那塊可以理解是 contentOffset 的改變隆豹。接下來(lái)是重點(diǎn)測(cè)試這塊啦椭岩,但是一直還是無(wú)法重現(xiàn)該崩潰。

四、偽解決它

測(cè)試了一整天判哥,就沒(méi)有崩潰一次献雅,從來(lái)沒(méi)有想到過(guò)有一天居然想讓自己的項(xiàng)目崩掉。塌计。挺身。
回顧一下,我們之前版本 和 這一版本在啟動(dòng)中做的改變锌仅,然后我更懵啦章钾,最后覺(jué)的一種可能是 這邊 self.viewModel 被提前釋放掉了,但我這是強(qiáng)引用叭惹邸贱傀!。剿吻。窍箍。(項(xiàng)目中用的 是MVVM)

暫時(shí)的做法: 增加更多的防空處理串纺。丽旅。。
??纺棺!同時(shí)我們這個(gè)項(xiàng)目被暫停下來(lái)啦榄笙,暫時(shí)都不會(huì)重新發(fā)版本啦,更不知道去如何解決它啦祷蝌。茅撞。。

PS更新:再次看聽(tīng)云巨朦,這幾天這個(gè) Bug 居然不重現(xiàn)了米丘,讓我更懵啦,只是出現(xiàn)一個(gè)類似這個(gè)bug的糊啡,就是具體崩潰軌跡有點(diǎn)不同拄查,真的懵了......

PS: 最有可能的原因

[self.collectionView performBatchUpdates:^{
      [self.collectionView insertItemsAtIndexPaths:indexPaths];
                    } completion:NULL];

根據(jù)崩潰信息,后來(lái)一朋友立馬想到是這個(gè)問(wèn)題棚蓄,就是UICollectionView插入 insertItemsAtIndexPaths的時(shí)候必須用一個(gè)方法堕扶,用到這個(gè) performBatchUpdates 的方法。

performBatchUpdates
- (void)performBatchUpdates:(void (^ __nullable)(void))updates completion:(void (^ __nullable)(BOOL finished))completion; // allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable.

allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable.

畢竟這個(gè)是蘋(píng)果推薦的稍算,之前沒(méi)有用,還是不對(duì)的役拴。雖說(shuō)無(wú)法證實(shí)糊探,無(wú)法重現(xiàn),但看后面那個(gè)注釋以及崩潰信息,感覺(jué)還是比較可靠的侧到。

五勃教、 總結(jié)

暫時(shí)這個(gè)問(wèn)題沒(méi)有解決它,沒(méi)法重現(xiàn)匠抗,但是還是先理一下這個(gè)過(guò)程的問(wèn)題和收獲故源。

  • 解決 bug 的思路歷程,需要再優(yōu)化汞贸;
  • 進(jìn)一步了解 Carsh 文件绳军,以及常見(jiàn)原因;
  • 對(duì) KVO 的實(shí)現(xiàn)矢腻,有了新的認(rèn)識(shí)门驾。

同時(shí),如有朋友知道上述類似問(wèn)題的解決方案多柑,歡迎告之奶是。

PS: 個(gè)人再次遇到這個(gè)BUG,有了些新理解竣灌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末聂沙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子初嘹,更是在濱河造成了極大的恐慌及汉,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屯烦,死亡現(xiàn)場(chǎng)離奇詭異坷随,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驻龟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門温眉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人翁狐,你說(shuō)我怎么就攤上這事类溢。” “怎么了谴蔑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵豌骏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我隐锭,道長(zhǎng)窃躲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任钦睡,我火速辦了婚禮蒂窒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己洒琢,他們只是感情好秧秉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著衰抑,像睡著了一般象迎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呛踊,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天砾淌,我揣著相機(jī)與錄音,去河邊找鬼谭网。 笑死汪厨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的愉择。 我是一名探鬼主播劫乱,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锥涕!你這毒婦竟也來(lái)了衷戈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤站楚,失蹤者是張志新(化名)和其女友劉穎脱惰,沒(méi)想到半個(gè)月后搏嗡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體窿春,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年采盒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旧乞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡磅氨,死狀恐怖尺栖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烦租,我是刑警寧澤延赌,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站叉橱,受9級(jí)特大地震影響挫以,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窃祝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一掐松、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦大磺、人聲如沸抡句。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)待榔。三九已至,卻和暖如春流济,著一層夾襖步出監(jiān)牢的瞬間究抓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工袭灯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刺下,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓稽荧,卻偏偏與公主長(zhǎng)得像橘茉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姨丈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

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