簡介
lldb提供了3種指令來打印變量溢谤,分別是po、p荞彼、v、今天我們就來看看這3種指令的實現(xiàn)方式和區(qū)別待笑。
po指令
po指令可以看成是打印變量的固定指令鸣皂,當我們使用po的時候,像上圖一樣我們得到的是文本形式的對象描述暮蹂。po不僅僅能打印變量签夭,還能像下圖一樣拿到對象的名字并計算名字的大寫版本。
事實上它可以計算任何表達式椎侠,其實po只是一個expression表達式的別名第租,你可以用command alias指令實現(xiàn)自定義的po指令
下面我們來看看po的底層是如何工作的
為了提供完整描述,首先它會根據(jù)你輸入的表達式生成一段代碼我纪,然后會在debug程序里編譯并執(zhí)行這段代碼來計算表達式的結(jié)果慎宾,LLDB拿到結(jié)果之后會生成另一短代碼來格式化結(jié)果輸出字符串
p指令
p指令和po指令打印出來的格式有點不一樣,但是內(nèi)容是一樣的浅悉。而且返回值被起名為R0, R0
下面讓我們看看p指令在后臺是如何運行的
事實上p指令底層的第一部分跟po指令是一樣的校摩,會先計算計算表達式的結(jié)果,一旦拿到結(jié)果LLDB會對結(jié)果執(zhí)行動態(tài)類型解析。至于什么是動態(tài)類型解析冯丙,可以用一個例子說明一下
在上面的例子中既绩,Trip遵守了Activity協(xié)議怠褐,在swift中源碼中的靜態(tài)類型和運行時的動態(tài)類型可以是不一樣的昌腰,像上面的例子一樣,可以用協(xié)議的類型去聲明cruise對象飞醉。cruise的靜態(tài)類型是Acitivity冲茸,但是運行時類型是Trip,如果我們打印cruise我們得到的也是Trip類型缅帘,因為LLDB會根據(jù)元數(shù)據(jù)展示給定變量的精確類型轴术。這就是動態(tài)類型解析
在p指令下,動態(tài)類型解析只會對表達式的結(jié)果執(zhí)行钦无,當我們想打印cruise的name的時候逗栽,這時cruise的類型是Activity,沒有name屬性铃诬,所以就會出錯祭陷,如果要消除錯誤可以把對象轉(zhuǎn)化為其動態(tài)類型
當對結(jié)果執(zhí)行完動態(tài)類型解析苍凛,LLDB會把解析的結(jié)果傳遞給格式化子系統(tǒng)來打印出可讀的字符串
如果你想之后沒有格式化的時候數(shù)據(jù)是什么樣,可以使用 expression --raw --指令查看
v指令
v指令的輸出也是依賴LLDB的格式化子系統(tǒng)兵志,v指令是在xcode10才引入的醇蝴,不像其他兩個指令,v不會編譯和執(zhí)行代碼想罕,所以v的執(zhí)行更快速悠栓。v指令有自己的語法,而且它的語法可以跟你在調(diào)試的程序的語言的語法不一樣按价。它可以用.和下標去獲取變量惭适。
v指令不能計算表達式,因為計算需要執(zhí)行代碼楼镐,如果要執(zhí)行計算表達式可以使用po或者p
v根據(jù)程序描述去在內(nèi)存種定位變量的位置癞志,然后從內(nèi)存中讀取變量,然后對結(jié)果執(zhí)行動態(tài)類型解析框产,當用于想訪問子字段凄杯,它就對每一個子字段重復(fù)執(zhí)行動態(tài)類型解析,一旦完成秉宿,就會把結(jié)果移交給格式化子系統(tǒng)戒突。
v可能會執(zhí)行多次動態(tài)類型解析,但是格式化只有一次描睦,只是在最后才格式化
總結(jié)
下面是三種指令的對比