高級(jí) LLDB 調(diào)試技能

作為session debugging with lldb的后續(xù)篇惫撰,session 413 advanced debugging with lldb的目的在于為了讓玩轉(zhuǎn)LLDB以盡調(diào)試之能事來(lái)進(jìn)行一些提綱挈領(lǐng)的引導(dǎo)。值得注意的是lldb的功能不僅限于為你提供流暢的調(diào)試服務(wù)顶籽,以幫你從煩心的bug中解脫出來(lái)葵腹,而且能夠作為你強(qiáng)有力的助手去探尋app華麗UI之下洶涌的暗流高每,而這一切都是為了制作出更加可靠的app屿岂。

眾所周知LLDB是作為GDB的替代者身份出現(xiàn)的,而其設(shè)計(jì)之初就是從底層基礎(chǔ)即可彈性擴(kuò)展以適應(yīng)今后的開(kāi)發(fā)鲸匿,從xcode5開(kāi)始爷怀,LLDB就開(kāi)始作為內(nèi)置調(diào)試器跟隨xcode發(fā)布。

除了對(duì)原有調(diào)試功能的優(yōu)化之外带欢,現(xiàn)在的LLDB相比于以前更加增強(qiáng)了數(shù)據(jù)監(jiān)控功能:包括對(duì)標(biāo)準(zhǔn)系統(tǒng)類型运授,foundation類型,C++標(biāo)準(zhǔn)庫(kù)類型及unicode text等信息在觀察的時(shí)候體驗(yàn) 需要再一次更新了乔煞,以前你可以搜尋到這些信息吁朦,但現(xiàn)在你想看到的信息就在你的眼前。

表達(dá)式解析器也得到了更新渡贾,雖然隨著語(yǔ)言特性的更新它也一直在更新逗宜,而我們遵從一個(gè)原則性的指導(dǎo):即我們希望用聲明來(lái)作為解析器。在LLDB中有一個(gè)健全的編譯器剥啤,正常的源代碼也能夠在LLDB中正常工作锦溪,任何新的語(yǔ)言特性都會(huì)在LLDB中得到支持不脯。

一個(gè)討巧的事情是在以前如果你輸入了一個(gè)表達(dá)式之后府怯,需要顯式地對(duì)result進(jìn)行類型轉(zhuǎn)換為其類型,以供LLDB在當(dāng)前的上下文中進(jìn)行探索定位防楷。而現(xiàn)在LLDB可以更多地對(duì)表達(dá)式進(jìn)行推理牺丙,從而省去了很多顯式類型轉(zhuǎn)換的書(shū)寫(xiě)。

用LLDB之前你要知道的

最佳的調(diào)試體驗(yàn)需要對(duì)調(diào)試器有很全面的了解复局,那就先來(lái)了解下吧冲簿。除了之后在著重介紹的觀察技巧比如:assertion,logging亿昏,static analysis峦剔,runtime memory tools之外,也需要重點(diǎn)關(guān)注單元測(cè)試角钩,因?yàn)閱卧獪y(cè)試可以告訴你應(yīng)用的哪些地方是有問(wèn)題的吝沫。除了這些之外,xcode的debug配置也是很重要的递礼,通常包括將生成調(diào)試信息的選項(xiàng)開(kāi)啟惨险,及關(guān)閉優(yōu)化等,以供調(diào)試的順利進(jìn)行脊髓。

避免常見(jiàn)的錯(cuò)誤

如果想斷點(diǎn)到某種場(chǎng)景辫愉,則最佳的做法不是先隨意打個(gè)斷點(diǎn)然后一直單步到出問(wèn)題的那行代碼,而是充分利用LLDB的特性以一次性定位到你所感興趣的代碼将硝。同時(shí)可以自定義你所想看到的數(shù)據(jù)恭朗,因?yàn)長(zhǎng)LDB默認(rèn)是只輸出系統(tǒng)類型的屏镊,而并不認(rèn)識(shí)自定義的數(shù)據(jù)類型,所以需要告訴LLDB你所關(guān)注的自定義數(shù)據(jù)類型及其數(shù)據(jù)冀墨。同時(shí)為了避免重新構(gòu)建所帶來(lái)的時(shí)間開(kāi)銷闸衫,你需要學(xué)會(huì)編寫(xiě)調(diào)試代碼,以改變應(yīng)用的執(zhí)行路徑诽嘉,并修改數(shù)據(jù)蔚出,比如初始化還未初始代的數(shù)據(jù)。

同時(shí)需要注意的是虫腋,你所輸入并執(zhí)行的表達(dá)式會(huì)改變應(yīng)用原本的執(zhí)行路徑骄酗,所以對(duì)此所帶來(lái)的副作用你需要有清晰的把控。

正確的調(diào)試過(guò)程

step 1 搞清楚希望通過(guò)LLDB知道的是什么

step 2 在可疑的地方停下來(lái)

step 3 在正在執(zhí)行的代碼中一步步執(zhí)行

step 4 觀察數(shù)據(jù)并驗(yàn)證猜想

什么時(shí)候用LLDB,LLDB能在調(diào)試的時(shí)候怎樣幫助你

發(fā)現(xiàn)bug時(shí)悦冀,LLDB并不是你的第一選擇趋翻,而應(yīng)該是debug-Only assertion,它能幫助你知道應(yīng)用中是否發(fā)生了不可能發(fā)生的事情盒蟆,以及各組件之間傳遞的參數(shù)是否與約定的一致踏烙。而同時(shí)需要注意的是不要在assertion中做對(duì)應(yīng)用邏輯有影響的操作,因?yàn)橐坏?gòu)建發(fā)布版本历等,這些assertion都會(huì)被屏幕讨惩,你在其中執(zhí)行的操作也就不會(huì)進(jìn)行了。

而對(duì)于在運(yùn)行中各處都看起來(lái)很正常寒屯,最終去呈現(xiàn)了錯(cuò)誤的結(jié)果的情況荐捻,log會(huì)是一個(gè)非常有用的工具。而此處的log指的并不是NSLog寡夹,而是apple system log(ASL)处面,其可以通過(guò)console觀察到。ASL可以通過(guò)log的level來(lái)區(qū)分log的嚴(yán)重程序菩掏,比如ASL_LEVEL_EMERG和ASL_LEVEL_DEBUG魂角。同時(shí)還可以附帶使用hash tag以方便log的查找,比如為特定的業(yè)務(wù)添加特定的業(yè)務(wù)字符串等智绸。而鑒于log可能被濫用野揪,所以ASL可以通過(guò)開(kāi)關(guān)提供某些log是否應(yīng)該進(jìn)行。正常的開(kāi)關(guān)方式可以是可以使用NSUserDefaults等传于,或者也可以在shell中設(shè)置一個(gè)變量囱挑,程序在運(yùn)行的時(shí)候讀取此值以決定是否進(jìn)行l(wèi)og。

Xcode可以為程序做的沼溜,-Weverything和靜態(tài)代碼分析器可以在代碼運(yùn)行前的編譯階段即發(fā)現(xiàn)可能存在的問(wèn)題平挑。可以在之前的session: What's New In LLVM和What's New In the LLVM Compiler中找到相關(guān)內(nèi)容。而在運(yùn)行期間可以通過(guò)Guard Malloc發(fā)現(xiàn)堆上緩存overrun的問(wèn)題通熄,通過(guò)zombie objects獲取對(duì)釋放了的對(duì)象進(jìn)行方法調(diào)用的問(wèn)題唆涝。具體可以參見(jiàn)Advanced Memory Analysis with Instruments

LLDB的正確打開(kāi)方式

現(xiàn)在正式開(kāi)始LLDB之旅,它有兩種操作方式唇辨,一種是通過(guò)xcode上的按鈕廊酣,另一種是通過(guò)console中的lldb調(diào)試語(yǔ)言。LLDB命令有3種形式赏枚,discoverable,abbreviated及alias形式亡驰,分別是演示如下:expression --object-description -- foo, e -0 -- foo饿幅,po foo凡辱。表達(dá)的是一個(gè)意思,但書(shū)寫(xiě)繁瑣程度遞減栗恩,而且可以定義自己的alias 形式的命令透乾。

斷點(diǎn)的設(shè)置方式有多種:

如果知道代碼行號(hào),可以直接在代碼界面點(diǎn)擊代碼行首處磕秤,命令像這樣: b MyCode.m:4(breakpoint set --file MyCode.m --line 4)

如果不知道代碼行號(hào)乳乌,則可以使用這樣的命令斷點(diǎn)在某方法處:b "-[MyClass method:]"(breakpoint set --name "-MyClass method:]")

如果想在任何對(duì)象收到特定selector時(shí)斷點(diǎn),可以這樣b method:(breakpoint set --selector method:)

省時(shí)的命令

鑒于在app及xcode之間因?yàn)槎啻沃袛喽M(jìn)行的多次切換市咆,可以在斷點(diǎn)發(fā)生之后執(zhí)行特定的命令汉操,比如查看希望查看的數(shù)據(jù)之后再立即恢復(fù)執(zhí)行,可以這樣

b "-[MyClass method:]"

br co a/breakpoint command add

>p rect/expression rect

>bt/thread backtrace

>c/process continue

>DONE

這些命令也可以在xcode面板中通過(guò)點(diǎn)擊及輸入完成同樣的功能床绪。

條件斷點(diǎn)

如果不希望斷點(diǎn)頻繁觸發(fā)客情,可以通過(guò)條件斷點(diǎn)來(lái)達(dá)到此目的其弊,比如想在某個(gè)特定對(duì)象析構(gòu)的消息處斷點(diǎn)癞己,可以這樣:

p id $myModel = self/expression id $myModel = self

b "-[MyClass dealloc]"/breakpoint set? "-[MyClass dealloc]"

br m -c "self == $myModel"/breakpoint modify --condition "self == $myModel"

通過(guò)watchpoint監(jiān)控特定內(nèi)存空間

watchpoint的應(yīng)用場(chǎng)景在于有人會(huì)修改某個(gè)變量值,你對(duì)此很關(guān)心但只知道變量的地址梭伐,其行為方式是如果變量被訪問(wèn)則watchpoint會(huì)暫停app的運(yùn)行痹雅,設(shè)置watchpoint的方式是

w s v self->_needsSynchronization/watchpoint set variable self->_needsSynchronization

受限于CPU的支持程度,在intel平臺(tái)上糊识,提供了4個(gè)slot供watchpoint使用绩社,所以同時(shí)只可設(shè)置最多4個(gè)watchpoint,arm上是2個(gè)

watchpoint也可以在xcode的控制面板中進(jìn)行操作赂苗,只需要在變量區(qū)域中右擊某變量選擇菜單中的watchpoint選項(xiàng)即可

避免不斷單步的高招

LLDB可以在兩種場(chǎng)景下暫停程序的執(zhí)行:

1 執(zhí)行到程序的具體某行代碼的時(shí)候

? ?這種場(chǎng)景的實(shí)用命令是thread until linenum愉耙,避免一步步單步執(zhí)行到希望的行,在xcode中這個(gè)功能對(duì)應(yīng)的操作是右擊代碼行選擇continue to this line拌滋。

2 函數(shù)返回之后

LLDB維護(hù)調(diào)試操作的上下文

如果單步過(guò)程中命中函數(shù)中的斷點(diǎn)朴沿,則直接continue會(huì)繼續(xù)單步到下一行

LLDB維護(hù)調(diào)試操作的上下文

如上圖中在單步到第9行時(shí),恰好其中removeDuplicates這個(gè)selector中也存在一個(gè)斷點(diǎn),此時(shí)選擇stepover赌渣,會(huì)停到這個(gè)selector中的斷點(diǎn)上魏铅,但這時(shí)候不要驚慌,使用continue命令此時(shí)會(huì)恰好斷點(diǎn)在第10行上坚芜。

LLDB中手動(dòng)執(zhí)行代碼

很多時(shí)候你可能會(huì)發(fā)現(xiàn)览芳,要想讓你希望執(zhí)行的代碼執(zhí)行一遍會(huì)很困難,比如單元測(cè)試的時(shí)候某個(gè)用例就是無(wú)法進(jìn)行測(cè)試鸿竖,這種情況下你需要用Clang(['kl^n])直接調(diào)用這份代碼沧竟,調(diào)用方式是直接在命令行表達(dá)式中輸入你希望執(zhí)行的代碼并執(zhí)行,比如

b "-[ModelDerived removeDuplicates]"

e -i false -- [self removeDuplicates]/expression --ignore-breakpoints false -- [self removeDuplicates]

先在方法上打斷點(diǎn)缚忧,然后在LLDB中執(zhí)行此函數(shù)屯仗,選擇不要忽略斷點(diǎn),你會(huì)發(fā)現(xiàn)執(zhí)行此expression之后會(huì)斷點(diǎn)到removeDuplicates搔谴,接著即可對(duì)其進(jìn)行執(zhí)行魁袜。

然而有一點(diǎn)需要特別注意的是,通過(guò)LLDB執(zhí)行的表達(dá)式代碼是在你的進(jìn)程中執(zhí)行的敦第,所以需要對(duì)此所帶來(lái)的后果有自己的認(rèn)知峰弹。

檢查數(shù)據(jù)以找尋事情的緣由

在上述的操作之后,我們已經(jīng)可以斷點(diǎn)到我們希望斷點(diǎn)的位置了芜果,接著就是檢查數(shù)據(jù)尋找事情發(fā)生的原因了鞠呈,這部分有3方面內(nèi)容:

在LLDB命令行中檢查數(shù)據(jù)

? 查看局部變量: frame variable

? 執(zhí)行任意代碼: expression (x+35) 其會(huì)通過(guò)app使用的編譯器進(jìn)行編譯并在你的app中執(zhí)行

? p @"hello" 兼容expression的語(yǔ)法,執(zhí)行表達(dá)式并輸出結(jié)果

? po @"hello" 執(zhí)行任意代碼并輸出結(jié)果的description?

LLDB實(shí)用數(shù)據(jù)格式

? 需要先搞清楚raw data和data的區(qū)別右钾,raw data就是內(nèi)存中所存儲(chǔ)的數(shù)據(jù)蚁吝,但它并不易讀,對(duì)你來(lái)說(shuō)可能太復(fù)雜舀射,或者并不是你理解的數(shù)據(jù)類型窘茁,又或者它的數(shù)據(jù)量很大。如果想對(duì)raw data有個(gè)直觀的印象脆烟,只需要在xcode的變量區(qū)域選擇show raw values就可以在觀察任意一個(gè)棧幀的時(shí)候看到raw data了山林,而此時(shí)切換到show types就可以看到規(guī)整而有意義的數(shù)據(jù)呈現(xiàn)形式了,這就是 LLDB 數(shù)據(jù)格式所要達(dá)到的目的。

對(duì)于內(nèi)置的系統(tǒng)庫(kù)STL,CoreFoundation,Foundation,其中的數(shù)據(jù)都已經(jīng)添加了Data formatter券腔,在調(diào)試的時(shí)候顯示都很規(guī)整

對(duì)于程序員自定義的數(shù)據(jù)類型的data formatter亿笤,蘋果構(gòu)建了可擴(kuò)展的data formatter子系統(tǒng),這意味著程序員也可以為自定義的類型添加data formatter。

自定義data formatter

數(shù)據(jù)類型的data formatter包括兩部分:綜述summary,用于呈現(xiàn)數(shù)據(jù)的關(guān)鍵描述;所組成的子數(shù)據(jù)即synthetic children

array右端的summary和3個(gè)數(shù)組synthetic children信息

以使用python定義summary為例明也,summary會(huì)將一種數(shù)據(jù)類型與一個(gè)python函數(shù)映射起來(lái),基礎(chǔ)的映射是通過(guò)類型名,更多其它規(guī)則可以參見(jiàn)http://lldb.llvm.org/varformats.html

這個(gè)python函數(shù)會(huì)在此類型的數(shù)據(jù)在展示的時(shí)候被調(diào)用诡右,LLDB會(huì)將一個(gè)SBValue傳遞給它安岂,SBValue是LLDB對(duì)象模型的一部分,可以將其簡(jiǎn)單地想象成為一個(gè)變量帆吻,這個(gè)python函數(shù)最終會(huì)返回一個(gè)字符串域那,這個(gè)字符串即會(huì)被當(dāng)做summary

SBValue

之前提到SBValue可以當(dāng)做一個(gè)變量來(lái)對(duì)待,可以詢問(wèn)其name,data type,summary(如果有的話),是否有children,有多少children,是否可以詳述每個(gè)child的信息,每個(gè)child的信息其實(shí)也是一個(gè)sbvalue猜煮,所以整個(gè)是一個(gè)遞歸的過(guò)程次员。如果值是一個(gè)比如數(shù)字這樣的標(biāo)量,整數(shù)王带,浮點(diǎn)數(shù)等淑蔚,也可以詢問(wèn)其value。

對(duì)自定義類進(jìn)行summary

def MyClass_Summary(value,unused)://其中value是一個(gè)SBValue

//由于是自己定義的數(shù)據(jù)愕撰,可先獲取其中的成員變量刹衫,成員變量也是SBValue

member1 = value.GetChildMemberWithName("_member1")

member2 = value.GetChildMemeberWithName("_member2")

member1Summary = member1.GetSummary()

member2Summary = member2.GetSummary()

#當(dāng)然也可以做任何你想做的事情,這里僅僅只是簡(jiǎn)單地組合兩個(gè)成員的summary

return member1Summary + " " + member2Summary

完成了這個(gè)python函數(shù)之后搞挣,變量區(qū)域中仍然不能正確顯示MyClass的自定義數(shù)據(jù)類型带迟,因?yàn)槟氵€需要在LLDB中執(zhí)行:

ty su a MyClass -F MyClass_Summary/type summary add MyClass --python-function MyClass_Summary

審視不透明的數(shù)據(jù)

先介紹下用于數(shù)據(jù)分析的expression,可以通過(guò)如下形式定義一個(gè)持久有效的結(jié)構(gòu)體:

?expression struct $NotOpaque{int item1;float item2;char* item3;}

對(duì)于第3方庫(kù)提供的對(duì)象囱桨,你可能連其數(shù)據(jù)類型都不知道仓犬,更不會(huì)知道其中成員變量的定義,可能通過(guò)google之后舍肠,可以發(fā)現(xiàn)其具體的定義搀继,這時(shí)候,就需要使用上述expression再結(jié)合summary翠语,即可以在展示的時(shí)候使用自定義的data formatter了

擴(kuò)展LLDB

自定義LLDB命令

通過(guò)python腳本叽躯,可以為調(diào)試器添加新特性,實(shí)現(xiàn)自定義的操作啡专,自動(dòng)化的操作過(guò)程

比如計(jì)算遞歸的層數(shù)险毁,想想LLDB怎么也算是個(gè)強(qiáng)大的程序制圈,數(shù)數(shù)對(duì)它來(lái)說(shuō)應(yīng)該不是什么難事们童,更加說(shuō)相比于你手工一個(gè)棧幀一個(gè)棧幀地?cái)?shù)了。

LLDB 對(duì)象模型

LLDB的強(qiáng)大在于它所使用的LLDB對(duì)象模型鲸鹦,我們稱其為"SB"(scripting bridge)慧库,這是個(gè)python API,xcode用其來(lái)構(gòu)建debugger的UI馋嗜,這意味著對(duì)你可以完全地通過(guò)LLDB腳本使用SB的所有功能齐板,同時(shí)其也有一套對(duì)調(diào)試session的描述:

LLDB對(duì)象模型中的調(diào)試模型

對(duì)于上述調(diào)試界面相信大家都比較熟悉,LLDB對(duì)象模型對(duì)其的描述是這樣:SBTarget即是調(diào)試中的target,接著在點(diǎn)擊了xcode中的運(yùn)行按鈕之后甘磨,這個(gè)target成為了一個(gè)活著的實(shí)體橡羞,對(duì)這個(gè)實(shí)體,你可以輸入济舆,點(diǎn)哪卿泽,點(diǎn)哪,點(diǎn)滋觉,這即是在機(jī)器底層上運(yùn)行的進(jìn)程稱為SBProcess签夭,進(jìn)程有著很多用來(lái)完成任務(wù)的thread,即SBThread椎侠,而SBThread會(huì)不停地執(zhí)行function第租,每個(gè)function都會(huì)而每次function調(diào)用都會(huì)對(duì)應(yīng)棧上的一幀,即SBFrame我纪,現(xiàn)在我們已經(jīng)了解到了描述程序運(yùn)行中的所有對(duì)象慎宾,接下來(lái)看看怎樣完成我們想完成的任務(wù)。

首先需要知道的是python命令是如何執(zhí)行的呢浅悉,python函數(shù)是與LLDB中的命令一一對(duì)應(yīng)的璧诵,LLDB看到這個(gè)命令的時(shí)候即會(huì)調(diào)用相應(yīng)的python命令,python命令的原型是這樣

def MyCommand_Impl(debugger,user_input,result,unused):

第一個(gè)參數(shù)debugger是一個(gè)SBDebugger

user_input是用戶輸入的python 字符串

result是SBCommandReturnObject仇冯,是用來(lái)反饋給LLDB的之宿,反饋執(zhí)行成功與否等信息

添加自定義的命令的方式如下:

co sc a foo -f foo/command script add foo --python-function foo

計(jì)算遞歸深度


完整的計(jì)算遞歸深度的python代碼

斷點(diǎn)操作

斷點(diǎn)的痛點(diǎn)在于它會(huì)不停在中斷程序的執(zhí)行,條件斷點(diǎn)會(huì)好一點(diǎn)苛坚,有了斷點(diǎn)action比被,我們可以只在自己關(guān)注的場(chǎng)景停下來(lái)

斷點(diǎn)action是將斷點(diǎn)與一個(gè)python函數(shù)聯(lián)系起來(lái),斷點(diǎn)命中的時(shí)候會(huì)調(diào)用此python函數(shù)泼舱,而其可以返回false以勾選斷點(diǎn)編輯界面中的continue選擇框以讓LLDB繼續(xù)運(yùn)行

此python函數(shù)的原型是

def break_on_deep_traversal(frame,bp_loc,unused):

frame 類型為SBFrame

bp_loc類型為SBBreakpointLocation

綁定python函數(shù)的命令是

br co a -s p -F foo 1 /breakpoint command add --script python --python-function foo 1

以遞歸過(guò)深時(shí)需要停止 這個(gè)功能為例


根據(jù)遞歸深度判斷是否需要暫停程序執(zhí)行

lldbinit

蘋果提供了這么多可以定制的功能等缀,如果一旦重啟xcode所有的自定義都回到解放前,我肯定欲哭無(wú)淚娇昙,不過(guò)別擔(dān)心尺迂,自定義可以固化在一個(gè)LLDB的配置文件中位于~/.lldbinit,在每個(gè)debug session啟動(dòng)時(shí)冒掌,都會(huì)加載此文件噪裕,在里面可以很方便地調(diào)整調(diào)試器設(shè)置,在里面也可以加載常用的腳本股毫。如果只想在用xcode啟動(dòng)lldb的時(shí)候才進(jìn)行這些加載膳音,則你需要的文件是~/.lldbinit-Xcode,在.lldbinit文件中可以進(jìn)行操作比如command script import 添加自定義的python文件铃诬,及命名自定義名字的lldb命令 command script add -f pythonmodule.funcname cmdname

后注:

Debug-only Assertions(NS_BLOCK_ASSERTIONS在開(kāi)發(fā)版中屏蔽assert)

NSAssert(_dictionary != nil,@"_dictionary should be initialized")

其實(shí)在Xcode 7.1中設(shè)置條件斷點(diǎn)時(shí)祭陷,需要顯式地將表達(dá)式轉(zhuǎn)換為BOOL型苍凛,比如添加條件為 [view clipsToBounds],未添加顯式類型轉(zhuǎn)換時(shí)兵志,斷點(diǎn)時(shí)會(huì)報(bào)錯(cuò):

error: no known method '-clipsToBounds:'; cast the message send to the method's return type

解決方案是添加顯式類型轉(zhuǎn)換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末醇蝴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子想罕,更是在濱河造成了極大的恐慌哑蔫,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弧呐,死亡現(xiàn)場(chǎng)離奇詭異闸迷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)俘枫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門腥沽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鸠蚪,你說(shuō)我怎么就攤上這事今阳。” “怎么了茅信?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵盾舌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蘸鲸,道長(zhǎng)妖谴,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任酌摇,我火速辦了婚禮膝舅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窑多。我一直安慰自己仍稀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布埂息。 她就那樣靜靜地躺著技潘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪千康。 梳的紋絲不亂的頭發(fā)上享幽,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音吧秕,去河邊找鬼琉闪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砸彬,可吹牛的內(nèi)容都是我干的颠毙。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼砂碉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蛀蜜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起增蹭,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤滴某,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后滋迈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體霎奢,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年饼灿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幕侠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碍彭,死狀恐怖晤硕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庇忌,我是刑警寧澤舞箍,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站皆疹,受9級(jí)特大地震影響疏橄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜略就,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一软族、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧残制,春花似錦立砸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至恼布,卻和暖如春螺戳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背折汞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工倔幼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爽待。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓损同,卻偏偏與公主長(zhǎng)得像翩腐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膏燃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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

  • 轉(zhuǎn)載 與調(diào)試器共舞 - LLDB 的華爾茲: https://objccn.io/issue-19-2/ 推薦:i...
    F麥子閱讀 3,331評(píng)論 0 10
  • [轉(zhuǎn)]淺談LLDB調(diào)試器文章來(lái)源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc閱讀 2,487評(píng)論 2 6
  • Xcode 上的lldb LLDB 調(diào)試工具茂卦,gdb替代品;LLVM : Low Level Virtual Ma...
    helinyu閱讀 914評(píng)論 0 2
  • 隨著Xcode 5的發(fā)布组哩,LLDB調(diào)試器已經(jīng)取代了GDB等龙,成為了Xcode工程中默認(rèn)的調(diào)試器。它與LLVM編譯器一...
    隨風(fēng)飄蕩的小逗逼閱讀 1,402評(píng)論 0 0
  • 你是否曾經(jīng)苦惱于理解你的代碼伶贰,而去嘗試打印一個(gè)變量的值蛛砰? NSLog(@"%@", whatIsInsideThi...
    paraneaeee閱讀 1,186評(píng)論 0 7