iOS中UITableview頻繁reloadData引起的崩潰

今天一上班 看到如下崩潰日志,發(fā)現(xiàn)還不在少數(shù)

libobjc.A.dylib objc_msgSend + 8
1 CoreFoundation    -[NSDictionary descriptionWithLocale:indent:] + 340
2 Foundation    _NSDescriptionWithLocaleFunc + 76
3 CoreFoundation    ___CFStringAppendFormatCore + 8384
4 CoreFoundation    _CFStringCreateWithFormatAndArgumentsAux2 + 244
5 CoreFoundation    _CFLogvEx2 + 152
6 CoreFoundation    _CFLogvEx3 + 156
7 Foundation    __NSLogv + 132
8 Foundation    NSLog + 32
9 UIKit -[UITableView reloadData] + 1612
10 DadaStaff    -[UITableView(MJRefresh) mj_reloadData] (UIScrollView+MJRefresh.m:146)
11 DadaStaff    dzn_original_implementation (UIScrollView+EmptyDataSet.m:611)

對于這個(gè)崩潰問題,筆者一開始研究的點(diǎn)在于前兩個(gè)方法刽沾,即descriptionWithLocale: indent:objc_msgSend。疑問主要在以下幾點(diǎn):

  1. 既然objc_msgSend是崩潰前的最后一個(gè)調(diào)用的方法尘分,那如何獲取崩潰點(diǎn)調(diào)用的方法名/類名
  2. 如果objc_msgSend不能定位到崩潰,那是否問題可能出在descriptionWithLocale: indent:

帶著這兩個(gè)疑問丸氛,筆者慢慢進(jìn)行這三個(gè)方法的拆解

objc_msgSend:

objc_msgSend方法大家都很熟悉了培愁,它的偽代碼如下:

id objc_msgSend(id self, SEL _cmd, ...) {
  Class class = object_getClass(self);
  IMP imp = class_getMethodImplementation(class, _cmd);
  return imp ? imp(self, _cmd, ...) : 0;
}

因?yàn)?code>objc_msgSend是用匯編寫的,針對不同架構(gòu)有不同的實(shí)現(xiàn)缓窜。如下為 x86_64 架構(gòu)下的源碼定续,可以在 objc-msg-x86_64.s 文件中找到:

ENTRY   _objc_msgSend
    MESSENGER_START

    NilTest NORMAL
    GetIsaFast NORMAL       // r11 = self->isa
    CacheLookup NORMAL      // calls IMP on success
    NilTestSupport  NORMAL
    GetIsaSupport      NORMAL
// cache miss: go search the method lists
LCacheMiss:
    // isa still in r11
    MethodTableLookup %a1, %a2  // r11 = IMP
    cmp %r11, %r11      // set eq (nonstret) for forwarding
    jmp *%r11           // goto *imp
    END_ENTRY   _objc_msgSend

這里面包含一些有意義的宏:

NilTest 宏,判斷被發(fā)送消息的對象是否為 nil 的禾锤。如果為 nil私股,那就直接返回 nil。這就是為啥也可以對 nil 發(fā)消息恩掷。
GetIsaFast宏可以『快速地』獲取到對象的 isa 指針地址(放到 r11 寄存器倡鲸,r10 會(huì)被重寫;在 arm 架構(gòu)上是直接賦值到 r9)
CacheLookup 這個(gè)宏是在類的緩存中查找 selector 對應(yīng)的 IMP(放到 r10)并執(zhí)行黄娘。如果緩存沒中峭状,那就得到 Class 的方法表中查找了。
MethodTableLookup 宏是重點(diǎn)逼争,負(fù)責(zé)在緩存沒命中時(shí)在方法表中負(fù)責(zé)查找 IMP:

.macro MethodTableLookup
    MESSENGER_END_SLOW
    SaveRegisters
    // _class_lookupMethodAndLoadCache3(receiver, selector, class)
    movq    $0, %a1
    movq    $1, %a2
    movq    %r11, %a3
    call    __class_lookupMethodAndLoadCache3
    // IMP is now in %rax
    movq    %rax, %r11
    RestoreRegisters
.endmacro

從上面的代碼可以看出方法查找 IMP 的工作交給了 OC 中的 _class_lookupMethodAndLoadCache3 函數(shù)宁炫,并將 IMP 返回(從 r11 挪到 rax)。最后在 objc_msgSend 中調(diào)用 IMP氮凝。
全局搜索_class_lookupMethodAndLoadCache3可以找到其實(shí)現(xiàn):

IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
    return lookUpImpOrForward(cls, sel, obj,
                              YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}

lookUpImpOrForward 調(diào)用時(shí)使用緩存參數(shù)傳入為 NO羔巢,因?yàn)橹耙呀?jīng)嘗試過查找緩存了。IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver) 實(shí)現(xiàn)了一套查找 IMP 的標(biāo)準(zhǔn)路徑罩阵,也就是在消息轉(zhuǎn)發(fā)(Forward)之前的邏輯竿秆。


后續(xù)的消息轉(zhuǎn)發(fā)流程筆者就不一一贅述了。主要是之前閱讀過這篇文章:
深入iOS系統(tǒng)底層之crash解決方法介紹
里面有說過通過objc_msgSend方法來找到崩潰點(diǎn)稿壁,但因?yàn)檫^程繁瑣幽钢,于是放棄。

descriptionWithLocale: indent:

-description :當(dāng)你輸出一個(gè)對象時(shí)會(huì)調(diào)用該函數(shù)傅是,如:NSLog(@"%@",model);
-debugDescription :當(dāng)你在使用 LLDB 在控制臺(tái)輸入 po model 時(shí)會(huì)調(diào)用該函數(shù)
-descriptionWithLocale: indent: :存在于 NSArray 或 NSDictionary 等類中匪燕。當(dāng)類中有這個(gè)函數(shù)時(shí),它的優(yōu)先級(jí)為 -descriptionWithLocale: indent: > -description

由以上分析可知喧笔,只有在調(diào)用NSLog方法后才可能調(diào)用descriptionWithLocale: indent:方法帽驯。但從筆者的源代碼分析并沒有顯示的調(diào)用NSLog方法,為什么會(huì)調(diào)用descriptionWithLocale: indent:并在其后發(fā)生崩潰书闸。久尋無果后也只能放棄該中可能性尼变。

最后抱著試試看的態(tài)度,只能搜最后一個(gè)可能引起崩潰的方法:

[UITableView reloadData]

這個(gè)方法我們再熟悉不過了浆劲,UITableView的reloadData方法用于刷新UITableView嫌术。然而最不可能是崩潰的原因的方法卻是發(fā)生崩潰的地方哀澈,在這里Reporting crash on UITableview reloadData,主要講述的就是由于多次調(diào)用reloadData方法引起的崩潰:

Hooray - finally found the reason for this elusive problem. The crash was being due to the user being in edit mode within a UITextfield within a cell in the table when the reloadData was being called (as a result of the user tapping elsewhere or rotating the iPad, which also called ReloadData).
I fixed the issue by preceeding any [self.tableView ReloadData] with [self.view endEditing:YES] to ensure that the keyboard was dismissed and cells were not in an edit mode.
Does make sense but what a nasty trap.

修改完后收工度气,等待上線后查看效果吧割按。

引用

iOS Kingdom — 模型信息輸出

Reporting crash on UITableview reloadData

讓我們來搞崩 Cocoa 吧(黑暗代碼)

深入iOS系統(tǒng)底層之crash解決方法介紹

Objective-C 消息發(fā)送與轉(zhuǎn)發(fā)機(jī)制原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市磷籍,隨后出現(xiàn)的幾起案子适荣,更是在濱河造成了極大的恐慌,老刑警劉巖择示,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晒旅,居然都是意外死亡栅盲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門废恋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谈秫,“玉大人,你說我怎么就攤上這事鱼鼓∧馓蹋” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵迄本,是天一觀的道長硕淑。 經(jīng)常有香客問我,道長嘉赎,這世上最難降的妖魔是什么置媳? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮公条,結(jié)果婚禮上拇囊,老公的妹妹穿的比我還像新娘。我一直安慰自己靶橱,他們只是感情好寥袭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著关霸,像睡著了一般传黄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上队寇,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天尝江,我揣著相機(jī)與錄音,去河邊找鬼英上。 笑死炭序,一個(gè)胖子當(dāng)著我的面吹牛啤覆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惭聂,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窗声,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辜纲?” 一聲冷哼從身側(cè)響起笨觅,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耕腾,沒想到半個(gè)月后见剩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扫俺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年苍苞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狼纬。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羹呵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疗琉,到底是詐尸還是另有隱情冈欢,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布盈简,位于F島的核電站凑耻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柠贤。R本人自食惡果不足惜拳话,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望种吸。 院中可真熱鬧弃衍,春花似錦、人聲如沸坚俗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猖败。三九已至速缆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恩闻,已是汗流浹背艺糜。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人破停。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓翅楼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親真慢。 傳聞我的和親對象是個(gè)殘疾皇子毅臊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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