小笨狼的LLDB技巧:chisel

jopen 8年前發布 | 19K 次閱讀 Objective-C開發 Objective-C

不玩LLDB,不知道chisel有多強大。chisel之于LLDB,就像iPhone之于手機,前者幾乎給后者重新下了一次定義。如果你還不知道什么是LLDB,請看我上一篇文章《小笨狼與LLDB的故事》。

安裝

安裝Homebrew

chisel的安裝需要使用Homebrew,如果還沒有安裝Homebrew,可以使用下面的命令安裝,如果你已經安裝了,可以跳過這一步

Objective-C

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

用Homebrew安裝chisel

搞定Homebrew之后,你就可以用他來安裝chisel了

Objective-C

brew update
brew install chisel
brewupdate
brewinstallchisel

官網的命令里有一個 brew update ,是用來更新Homebrew版本的,如果你是新安裝的Homebrew,可以省略掉這條命令

在 ~/.lldbinit 中添加命令

安裝好之后,terminal中會出現這個東西

Objective-C

==> Caveats
Add the following line to ~/.lldbinit to load chisel when Xcode launches:
  command script import /usr/local/opt/chisel/libexec/fblldb.py
==> Caveats
Add thefollowinglineto ~/.lldbinittoloadchiselwhenXcode launches:
  command scriptimport /usr/local/opt/chisel/libexec/fblldb.py

意思是需要把這個命令 command script import /usr/local/opt/chisel/libexec/fblldb.py 加到 ~/.lldbinit 文件中

我們將命令其添加進去即可。如果你已經添加過一次了,不需要再次添加

Objective-C

touch ~/.lldbinit
echo "command script import /usr/local/opt/chisel/libexec/fblldb.py" >> ~/.lldbinit
touch ~/.lldbinit
echo "command script import /usr/local/opt/chisel/libexec/fblldb.py" >> ~/.lldbinit

重啟一下Xcode,安裝完成

更新

如果你想更新chisel,只需要輸入更新的命令即可

Objective-C

brew upgrade chisel
brewupgradechisel

命令

Autolayout

autolayout中有一種bug叫 Ambiguous Layouts ,意思是你設置的約束不足以確定view的位置或大小。比如你只設置了X軸的位置,沒有設置Y軸的位置

autolayout提供了專門判斷和查找這類問題的方法:

Objective-C

hasAmbiguousLayout. Available for both iOS and OS X. Call this method on a misplaced view. It returns YES if the view’s frame is ambiguous. Otherwise, it returns NO.
_autolayoutTrace. Available as a private method in iOS. Call this method on a view. It returns a string with diagnostic information about the entire view hierarchy containing that view. Ambiguous views are labeled, and so are views that have translatesAutoresizingMaskIntoConstraints set to YES.
hasAmbiguousLayout. Available forbothiOSandOS X. Call thismethodon a misplacedview. It returnsYES if theview’s frameisambiguous. Otherwise, itreturnsNO.
_autolayoutTrace. Available as a privatemethodin iOS. Call thismethodon a view. It returns a stringwithdiagnosticinformationabouttheentireviewhierarchycontainingthatview. Ambiguous viewsarelabeled, andsoareviewsthathavetranslatesAutoresizingMaskIntoConstraintssettoYES.
  • hasAmbiguousLayout 用于判斷是否存在 Ambiguous Layouts
  • _autolayoutTrace 用于查找存在的 Ambiguous Layouts

但是即使有查找的方法,真正去做這個事兒也比較費時費力的,這時候chisel給我們提供了更為方便的命令

alamborder

給存在 Ambiguous Layouts 的view加上border,方便查找哪些View存在問題

語法:

Objective-C

Syntax: alamborder [--color=color] [--width=width]
Syntax: alamborder [--color=color] [--width=width]
  • --color / -c : border的顏色,參數為string類型,比如’red’, ‘green’, ‘magenta’等,不設置默認為紅色。
  • --width / -w : border的寬度,參數為CGFloat類型,不設置默認寬度為2。

e.g: 假設我們寫了這么一段代碼,可以明顯看出,我們沒有設置X軸的位置。

Objective-C

UIView *subview = [UIView new];
[self.view addSubview:subview];
[subview mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.offset(100);
    make.size.equalTo(@100);
}];
UIView *subview = [UIView new];
[self.viewaddSubview:subview];
[subviewmas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.offset(100);
    make.size.equalTo(@100);
}];

運行代碼之后,在LLDB控制臺輸入 alamborder

Objective-C

(lldb) alamborder
(lldb) alamborder

所有帶有 Ambiguous Layouts 的view立即會被渲染上紅色border

可以看到,subview的邊框已經變為紅色,另外只要有一個View存在 Ambiguous Layouts ,UIWindow的邊框也會變為紅色,這就有效的避免了寬度或者高度為0的 Ambiguous Layouts 不宜察覺的缺陷。

alamunborder

將 alamborder 設置的border去掉.

語法:

Objective-C

Syntax: alamunborder
Syntax: alamunborder

e.g: 剛剛設置的border,在lldb控制臺輸入 alamunborder 即可去掉邊框

Objective-C

(lldb) alamborder
(lldb) alamborder

paltrace

打印某個View的autolayout詳細信息,相當于調用 _autolayoutTrace

語法:

Objective-C

Syntax: paltrace <view>
Syntax: paltrace <view>
  • <view> : 需要打印詳細信息的view,不傳參數默認為keyWindow

e.g: 查看一下keyWindow上有哪個view存在 Ambiguous Layouts

Objective-C

(lldb) paltrace ?UIWindow:0x7ff450d2fb50 - AMBIGUOUS LAYOUT | ?UIView:0x7ff450e14430 | | _UILayoutGuide:0x7ff450d30e90 | | _UILayoutGuide:0x7ff450d31230 | | *UIView:0x7ff450d32870- AMBIGUOUS LAYOUT for UIView:0x7ff450d32870.minX{id: 46}

Legend: * - is laid out with auto layout + - is laid out manually, but is represented in the layout engine because translatesAutoresizingMaskIntoConstraints = YES ? - layout engine host

(lldb) paltrace 
?UIWindow:0x7ff450d2fb50 - AMBIGUOUS LAYOUT
|  ?UIView:0x7ff450e14430
|  |  *_UILayoutGuide:0x7ff450d30e90
|  |  *_UILayoutGuide:0x7ff450d31230
|  |  *UIView:0x7ff450d32870- AMBIGUOUS LAYOUT forUIView:0x7ff450d32870.minX{id: 46}
 
Legend:
    * - islaidout withautolayout
    + - islaidout manually, butisrepresentedin thelayoutenginebecausetranslatesAutoresizingMaskIntoConstraints = YES
    ? - layoutenginehost

我們可以看到, UIView:0x7ff450d32870 存在 Ambiguous Layouts ,原因是缺少 minX 。也就是沒有設置X軸的位置

Print

在LLDB中,我們執行的最多的可能就是打印操作了,chisel專門為這類操作封裝了一些打印命令

pviews

循環打印view層級,正常情況下等效于調用 recursiveDescription 命令

Objective-C

// 下面2條命令等效
(lldb) po [self.view recursiveDescription]
(lldb) pviews self.view
// 下面2條命令等效
(lldb) po [self.viewrecursiveDescription]
(lldb) pviewsself.view

語法:

Objective-C

pviews [--up] [--depth=depth] <aView>
pviews [--up] [--depth=depth] <aView>
  • --up / -u : 以view為起始位置,向上打印,直到打印到window層
  • --depth / -d : 傳入int類型,表示打印的層數,0表示沒有限制

e.g: 打印一下self.view層級

Objective-C

(lldb) pviews self.view
<UIView: 0x7fee7ae1fa60; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fee7ae1d3c0>>
   | <UIButton: 0x7fee7ae1dd90; frame = (54 244; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1e300>>
   | <UIView: 0x7fee7ae1f2e0; frame = (35 312; 240 128); autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1f660>>
   | <_UILayoutGuide: 0x7fee7ae1fc20; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae20030>>
   | <_UILayoutGuide: 0x7fee7ae20b30; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae1d100>>
   | <UILabel: 0x7fee7ae1d3f0; frame = (0.4 150; 58.25 20.5); text = 'aaa'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fee7ae1bb30>>
(lldb) pviewsself.view
<UIView: 0x7fee7ae1fa60; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fee7ae1d3c0>>
  | <UIButton: 0x7fee7ae1dd90; frame = (54 244; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1e300>>
  | <UIView: 0x7fee7ae1f2e0; frame = (35 312; 240 128); autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1f660>>
  | <_UILayoutGuide: 0x7fee7ae1fc20; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae20030>>
  | <_UILayoutGuide: 0x7fee7ae20b30; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae1d100>>
  | <UILabel: 0x7fee7ae1d3f0; frame = (0.4 150; 58.25 20.5); text = 'aaa'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fee7ae1bb30>>

pvc

循環打印viewController的層級

語法:

Objective-C

Syntax: pvc <aViewController>
Syntax: pvc <aViewController>

<aViewController> : 表示要打印的viewController,不傳參數默認viewController為當前的VC

e.g: 打印一下當前VC

Objective-C

(lldb) pvc
<UINavigationController 0x7fce1a03d800>, state: appeared, view: <UILayoutContainerView 0x7fce19500c00>
   | <ViewController 0x7fce1c03a1d0>, state: disappeared, view: <UIView 0x7fce19517b40> not in the window
   | <TableViewController 0x7fce1951f7b0>, state: appeared, view: <UIView 0x7fce1c053e60>
(lldb) pvc
<UINavigationController 0x7fce1a03d800>, state: appeared, view: <UILayoutContainerView 0x7fce19500c00>
  | <ViewController 0x7fce1c03a1d0>, state: disappeared, view: <UIView 0x7fce19517b40> notin thewindow
  | <TableViewController 0x7fce1951f7b0>, state: appeared, view: <UIView 0x7fce1c053e60>

pclass

循環打印class的繼承關系

語法:

Objective-C

Syntax: pclass <object>
Syntax: pclass <object>

<object> : 要打印繼承關系的對象

e.g: 打印一個View對象的繼承關系

Objective-C

(lldb) pclass [UIView new]
UIView
   | UIResponder
   |    | NSObject
(lldb) pclass [UIView new]
UIView
  | UIResponder
  |    | NSObject

presponder

打印響應鏈

語法:

Objective-C

Syntax: presponder <startResponder>
Syntax: presponder <startResponder>

<startResponder> : UIResponder對象,響應鏈開始位置

e.g: 打印一個tableView的響應鏈

Objective-C

(lldb) presponder tableView
<UITableView: 0x7fde54810e00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fde52519ac0>; layer = <CALayer: 0x7fde5253b4c0>; contentOffset: {0, 0}; contentSize: {0, 220}>
   | <UIView: 0x7fde5255c710; frame = (0 0; 600 600); autoresize = W+H; layer = <CALayer: 0x7fde5253b300>>
   |    | <TableViewController: 0x7fde52491310>
(lldb) prespondertableView
<UITableView: 0x7fde54810e00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fde52519ac0>; layer = <CALayer: 0x7fde5253b4c0>;contentOffset: {0, 0};contentSize: {0, 220}>
  | <UIView: 0x7fde5255c710; frame = (0 0; 600 600); autoresize = W+H; layer = <CALayer: 0x7fde5253b300>>
  |    | <TableViewController: 0x7fde52491310>

ptv

打印屏幕中顯示的tableView,主要是與 pcells 聯合使用。如果有多個tableView,打印View層級中最上面的一個

語法:

Objective-C

Syntax: ptv
Syntax: ptv

e.g: 看看當前最上面是哪個tableView

Objective-C

(lldb) ptv
<UITableView: 0x7fde52811800; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fde526418d0>; layer = <CALayer: 0x7fde5260adc0>; contentOffset: {0, -64}; contentSize: {414, 176}>
(lldb) ptv
<UITableView: 0x7fde52811800; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fde526418d0>; layer = <CALayer: 0x7fde5260adc0>;contentOffset: {0, -64};contentSize: {414, 176}>

pcells

打印tableView中當前可見的cell,如果有多個tableView,打印View層級中最上面的tableView的可見cell

語法:

Objective-C

Syntax: pcells
Syntax: pcells

e.g: 看看當前可見的cell有哪些

Objective-C

(lldb) pcells
<__NSArrayI 0x7fde52565a00>(
<UITableViewCell: 0x7fde52551180; frame = (0 0; 414 44); text = 'BasicViewController'; autoresize = W; layer = <CALayer: 0x7fde52537140>>,
<UITableViewCell: 0x7fde5255bea0; frame = (0 44; 414 44); text = 'DateViewController'; autoresize = W; layer = <CALayer: 0x7fde5255b1a0>>,
<UITableViewCell: 0x7fde5255e2d0; frame = (0 88; 414 44); text = 'PPTViewController'; autoresize = W; layer = <CALayer: 0x7fde5255e270>>,
<UITableViewCell: 0x7fde5255fce0; frame = (0 132; 414 44); text = 'TableViewController'; autoresize = W; layer = <CALayer: 0x7fde5255fa90>>
)
(lldb) pcells
<__NSArrayI 0x7fde52565a00>(
<UITableViewCell: 0x7fde52551180; frame = (0 0; 414 44); text = 'BasicViewController'; autoresize = W; layer = <CALayer: 0x7fde52537140>>,
<UITableViewCell: 0x7fde5255bea0; frame = (0 44; 414 44); text = 'DateViewController'; autoresize = W; layer = <CALayer: 0x7fde5255b1a0>>,
<UITableViewCell: 0x7fde5255e2d0; frame = (0 88; 414 44); text = 'PPTViewController'; autoresize = W; layer = <CALayer: 0x7fde5255e270>>,
<UITableViewCell: 0x7fde5255fce0; frame = (0 132; 414 44); text = 'TableViewController'; autoresize = W; layer = <CALayer: 0x7fde5255fa90>>
)

pinternals

打印一個對象內部的成員變量,這個方法我一般用來看model屬性

語法:

Objective-C

Syntax: pinternals <object>
Syntax: pinternals <object>
  • <object> : 需要打印內部成員變量的對象

e.g: 我們來看看一個 model 內部屬性的值

Objective-C

(lldb) pinternals model
(Model) $5 = {
  _name = 0x000000010dd1c0a0 @"老鼠愛大米"
  _URL = nil
  _array = nil
  _dictionary = nil
  _string = nil
  _model = nil
}
(lldb) pinternalsmodel
(Model) $5 = {
  _name = 0x000000010dd1c0a0 @"老鼠愛大米"
  _URL = nil
  _array = nil
  _dictionary = nil
  _string = nil
  _model = nil
}

pdata

對編碼過的NSData進行解碼打印,等效于調用 -[NSString initWithData:encoding:]

語法:

Objective-C

Syntax: pdata [--encoding=encoding] <data>
Syntax: pdata [--encoding=encoding] <data>
  • <data> : 需要打印的data,NSData類型
  • --encoding / -e : 編碼類型,如果缺省默認為utf8,主要支持的類型有:

Objective-C

- ascii,
- utf8,
- utf16, unicode,
- utf16l (Little endian),
- utf16b (Big endian),
- utf32,
- utf32l (Little endian),
- utf32b (Big endian),
- latin1, iso88591 (88591),
- latin2, iso88592 (88592),
- cp1251 (1251),
- cp1252 (1252),
- cp1253 (1253),
- cp1254 (1254),
- cp1250 (1250),
- ascii,
- utf8,
- utf16, unicode,
- utf16l (Little endian),
- utf16b (Big endian),
- utf32,
- utf32l (Little endian),
- utf32b (Big endian),
- latin1, iso88591 (88591),
- latin2, iso88592 (88592),
- cp1251 (1251),
- cp1252 (1252),
- cp1253 (1253),
- cp1254 (1254),
- cp1250 (1250),

e.g: 將一個utf8的NSData打印

Objective-C

(lldb) pdata -e=utf8 data
老鼠愛大米
(lldb) pdata -e=utf8data
老鼠愛大米

pkp

通過 -valueForKeyPath: 打印 key path 對應的值。

語法:

Objective-C

Syntax: pkp <keypath>
Syntax: pkp <keypath>
  • <keypath> : 需要打印的路徑,如 self.view

說明:以前打印屬性一般都用 po obj.xxx ,現在我想用 pkp obj.xxx 是一個更好的選擇了,因為 po obj.xxx 是調用getter方法,如果沒有getter方法就無法打印了。 pkp obj.xxx 不僅會調用getter方法,沒有getter方法還會去查找成員變量

e.g: 打印一下self.view

Objective-C

(lldb) pkp self.view
<UIView: 0x7fd1da52d5d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fd1da52d740>>
(lldb) pkpself.view
<UIView: 0x7fd1da52d5d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fd1da52d740>>

pivar

打印對象成員變量

語法:

Objective-C

Syntax: pivar <object> <ivarName>
Syntax: pivar <object> <ivarName>
  • <object> : id類型,要打印成員變量的對象
  • <ivarName> : 成員變量的名稱,注意:如果是屬性,對應成員變量的名字默認有 _ 前綴.

說明:個人覺得這個方法有點雞肋, pinternals 一下子可以打印出所有的成員變量,用起來更方便,如果你只想打印某一個成員變量,用 pkp 應該更爽

e.g: 繼續打印self.view

Objective-C

(lldb) pivar self _view
<UIView: 0x7fd1da52d5d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fd1da52d740>>
(lldb) pivarself _view
<UIView: 0x7fd1da52d5d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fd1da52d740>>

pca

從渲染服務器的角度來打印 layer tree ,命令的完整名字是 PrintCoreAnimationTree ,相當于調用 po [NSString stringWithCString:(char *)CARenderServerGetInfo(0, 2, 0)]

語法:

Objective-C

Syntax: pca
Syntax: pca

說明:這個命令我也沒用過,可能在某些情況下會有用處

e.g: 試一下pca

Objective-C

(lldb) pca
== context 956ecbbf; level 0; pid 28092 [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard] (secure) at time 34552.989286 ==

(layer [375 667 0] [0 0 375 667] [0.5 0.5 0]
  (transform [2 -0 0 0; 0 2 0 0; 0 0 1 0; 0 0 0 1])
  (rasterizationScale 2)
  (sublayers (array
    (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
      (masksToBounds true)
      (sublayers (array
        (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
          (backgroundColor #000000ff)
          (sublayers (array
            (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
              (sublayers (array
                (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                  (sublayers (array
                    (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                      (sublayers (array
                        (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                          (masksToBounds true)
                          (edgeAntialiasingMask 0)
                          (subclass (layer-host adc504e5
                            ....東西太多,省略部分內容.........
(lldb) pca
== context 956ecbbf; level 0; pid 28092 [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard] (secure) attime 34552.989286 ==
 
(layer [375 667 0] [0 0 375 667] [0.5 0.5 0]
  (transform [2 -0 0 0; 0 2 0 0; 0 0 1 0; 0 0 0 1])
  (rasterizationScale 2)
  (sublayers (array
    (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
      (masksToBoundstrue)
      (sublayers (array
        (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
          (backgroundColor #000000ff)
          (sublayers (array
            (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
              (sublayers (array
                (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                  (sublayers (array
                    (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                      (sublayers (array
                        (layer [187.5 333.5 0] [0 0 375 667] [0.5 0.5 0]
                          (masksToBoundstrue)
                          (edgeAntialiasingMask 0)
                          (subclass (layer-hostadc504e5
                            ....東西太多,省略部分內容.........

panim

顯示是否正在執行動畫,相當于調用 p (BOOL)[UIView _isInAnimationBlock]

語法:

Objective-C

Syntax: panim
Syntax: panim

說明:這個命令也并不常用

e.g: 在動畫中,我們打印一下:

Objective-C

(lldb) panim
(BOOL) $0 = YES
(lldb) panim
(BOOL) $0 = YES

Find

debug的時候,我們經常需要查找一些東西,比如View,viewController等。

fvc

根據viewController的Class名字查找VC

語法:

Objective-C

Syntax: fvc [--name=classNameRegex] [--view=view]
Syntax: fvc [--name=classNameRegex] [--view=view]
  • --name / -n : string類型參數,根據viewController的Class名字查找viewController
  • --view / -v : UIView類型參數,根據viewController擁有的view查找viewController

說明:上面2個option不能同時使用,只能使用某一個

e.g: 我們先根據名字查找一下VC

Objective-C

(lldb) fvc --name=viewcontroller
0x7fd01a90f310 ViewController
(lldb) fvc --name=viewcontroller
0x7fd01a90f310 ViewController

e.g: 如果我們知道VC的view地址,也可以根據view來查找VC

Objective-C

(lldb) fvc --view=0x7fd0194194d0
Found the owning view controller.
<ViewController: 0x7fd01a90f310>
(lldb) fvc --view=0x7fd0194194d0
Found theowningviewcontroller.
<ViewController: 0x7fd01a90f310>

fv

根據view的class名字查找view

語法:

Objective-C

Syntax: fv <classNameRegex>
Syntax: fv <classNameRegex>
  • <classNameRegex> : view的class名稱

e.g: 查找一下屏幕上的UILabel

Objective-C

(lldb) fv uilabel
0x7fd01a91dc10 UILabel
(lldb) fvuilabel
0x7fd01a91dc10 UILabel

taplog

將點擊的view打印出來,這個命令對于查找哪個view非常有幫助

語法:

Objective-C

Syntax: taplog
Syntax: taplog

說明:要查看的view必須能接收點擊事件,也就是他的 userInteractionEnabled 必須為YES才能被找到,UILabel和UIImageView默認 userInteractionEnabled 為NO。

用法:我們需要先將程序暫停,輸入 taplog ,程序會自己運行,這時候點擊你需要查看的view,控制臺上就會顯示出你剛剛點擊的view相關信息

e.g: 我們先將程序暫停,輸入 taplog

Objective-C

(lldb) taplog
Process 28421 resuming
(lldb) taplog
Process 28421 resuming

程序會自己運行,我們再點擊一個UIButton:

Objective-C

<UIButton: 0x7fe6785284e0; frame = (54 244; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fe678528a50>>
<UIButton: 0x7fe6785284e0; frame = (54 244; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fe678528a50>>

flicker

將view閃爍一下,以便于查找view的位置

語法:

Objective-C

Syntax: flicker <viewOrLayer>
Syntax: flicker <viewOrLayer>
  • <viewOrLayer> 需要閃爍的view或者layer

e.g: 我們來看看self.subView的位置

Objective-C

(lldb) flicker self.subView
(lldb) flickerself.subView

vs

在view層級中搜索view,并顯示出來

語法:

Objective-C

Syntax: vs <view>
Syntax: vs <view>
  • <view> :要查找的view

說明:相比 fv , vs 主要用于顯示view在屏幕上的位置,2個命令可以配合使用

e.g: 假設我們要找屏幕上的一個view

首先用 fv 查找 UIView 類型的view

Objective-C

(lldb) fv uiview
0x7fbcf37228d0 UIView
0x7fbcf3725e90 UIView
(lldb) fvuiview
0x7fbcf37228d0 UIView
0x7fbcf3725e90 UIView

然后看看這2個view到底哪個是我們想要找的view

Objective-C

(lldb) vs 0x7fbcf3725e90

Use the following and (q) to quit.
(w) move to superview
(s) move to first subview
(a) move to previous sibling
(d) move to next sibling
(p) print the hierarchy

<UIView: 0x7fbcf3725e90; frame = (0 100; 100 100); layer = <CALayer: 0x7fbcf3712a40>>
(lldb) vs 0x7fbcf3725e90
 
Use thefollowingand (q) toquit.
(w) movetosuperview
(s) movetofirstsubview
(a) movetoprevioussibling
(d) movetonextsibling
(p) printthehierarchy
 
<UIView: 0x7fbcf3725e90; frame = (0 100; 100 100); layer = <CALayer: 0x7fbcf3712a40>>

輸入命令后他會幫我們在屏幕上用粉紅色標志出來 vs 的view

控制臺中 vs 的view也有相應log。并且還提示有6種子命令:

  • w : 移動到superview
  • s : 移動到第一個subview
  • a : 移動到前面的同級view
  • d : 移動到后面的同級view
  • p : 打印出層級
  • q : 退出

如果這個不是我們要找的view,可以使用 w , s , a , d , p 命令繼續查找

Display

debug的時候,可能有一小半的工作是跟UI打交道,關于UI顯示上的東西,也有幾個命令

caflush

刷新UI界面。一般我們用LLDB命令改變UI,UI并不會立即更新,我們需要使用 caflush 刷新界面

語法:

Objective-C

Syntax: caflush
Syntax: caflush

e.g: 我們用命令將label的背景色改為紅色

Objective-C

(lldb) fv uilabel
0x7fb3919189d0 UILabel
(lldb) e [((UILabel*)0x7fb3919189d0) setBackgroundColor:[UIColor redColor]]
(lldb) caflush
(lldb) fvuilabel
0x7fb3919189d0 UILabel
(lldb) e [((UILabel*)0x7fb3919189d0) setBackgroundColor:[UIColor redColor]]
(lldb) caflush

border

給View或者layer加上border

語法:

Objective-C

Syntax: border [--color=color] [--width=width] <viewOrLayer>
Syntax: border [--color=color] [--width=width] <viewOrLayer>
  • --color / -c : 邊框顏色,string類型,比如:’red’, ‘green’ ‘magenta’等,不設置默認為紅色
  • --width / -w : 邊框寬度,不設置默認為2
  • <viewOrLayer> : 需要設置邊框的view或者layer

e.g: 給剛剛的label加上邊框

Objective-C

(lldb) fv uilabel
0x7fe713901f10 UILabel
(lldb) border 0x7fe713901f10
(lldb) fvuilabel
0x7fe713901f10 UILabel
(lldb) border 0x7fe713901f10

unborder

去掉view或者layer的border

語法:

Objective-C

Syntax: unborder <viewOrLayer>
Syntax: unborder <viewOrLayer>

e.g: 將剛剛加上的border去掉

Objective-C

(lldb) unborder 0x7fe713901f10
(lldb) unborder 0x7fe713901f10

mask

給view添加一個半透明的矩形mask,用來查看view的位置

語法:

Objective-C

Syntax: mask [--color=color] [--alpha=alpha] <viewOrLayer>
Syntax: mask [--color=color] [--alpha=alpha] <viewOrLayer>
  • --color / -c : mask的顏色,string類型,比如:’red’, ‘green’,'magenta’等,不設置默認為紅色
  • --alpha / -a : mask的透明度,不設置默認為0.5
  • <viewOrLayer> : 需要添加mask的view或者layer

e.g: 假如label是隱藏的,我們給他添加一個mask,看看他的位置在哪兒

Objective-C

(lldb) fv uilabel
0x7fe713901f10 UILabel
(lldb) mask 0x7fe713901f10
(lldb) fvuilabel
0x7fe713901f10 UILabel
(lldb) mask 0x7fe713901f10

unmask

將添加的mask去掉

語法:

Objective-C

Syntax: unmask <viewOrLayer>
Syntax: unmask <viewOrLayer>
  • <viewOrLayer> : 需要去掉mask的view或者layer

e.g: 我們將剛剛添加的mask去掉

Objective-C

(lldb) unmask 0x7fe713901f10
(lldb) unmask 0x7fe713901f10

使用命令之后,我們可以看到什么都沒有了,因為label是hidden的

show

顯示一個view或者layer,相當于執行 view.hidden = NO

語法:

Objective-C

Syntax: show <viewOrLayer>
Syntax: show <viewOrLayer>
  • <viewOrLayer> : 需要顯示的view或者layer

e.g: 將剛剛的label顯示出來

Objective-C

(lldb) show 0x7fe713901f10
(lldb) show 0x7fe713901f10

hide

隱藏一個view或者layer,相當于執行 view.hidden = YES

語法:

Objective-C

Syntax: hide <viewOrLayer>
Syntax: hide <viewOrLayer>
  • <viewOrLayer> : 需要隱藏的view或者layer

e.g: 又把label隱藏

Objective-C

(lldb) hide 0x7fe713901f10
(lldb) hide 0x7fe713901f10

可以看到label位置什么都沒有了

slowanim

減慢動畫的速度

語法:

Objective-C

Syntax: slowanim <speed>
Syntax: slowanim <speed>
  • <speed> : 動畫的速度,速度越大,動畫越快。1表示原始速度。不傳參數默認為0.1

e.g: 原始動畫我們設置為1s

Objective-C

[UIView animateWithDuration:1 animations:^{
    self.subView.frame = frame;
}];
[UIViewanimateWithDuration:1animations:^{
    self.subView.frame = frame;
}];

暫停程序,將動畫放慢5倍

Objective-C

(lldb) slowanim 0.2
(lldb) slowanim 0.2

我們可以看到動畫變慢了:

unslowanim

取消 slowanim 效果,將動畫速度變為正常

語法:

Objective-C

Syntax: unslowanim
Syntax: unslowanim

e.g: 我們將剛剛的 slowanim 效果取消

Objective-C

(lldb) unslowanim
(lldb) unslowanim

Preview

預覽功能,幫助我們用命令查看一個view或者圖片的真正樣子

visualize

用預覽App打開UIImage, CGImageRef, UIView, CALayer等對象

語法:

Objective-C

Syntax: visualize <target>
Syntax: visualize <target>
  • <target> : 需要預覽的對象,id類型

e.g: 我們來看看某個image的樣子

Objective-C

(lldb) visualize image
(lldb) visualizeimage

Debug

LLDB主要用于Debug,chisel怎么可能缺少debug相關命令呢?

wivar

為對象的成員變量設置 watchpoint ,更多 watchpoint 相關知識請閱讀 <小笨狼與LLDB的故事>

語法:

Objective-C

Syntax: wivar <object> <ivarName>
Syntax: wivar <object> <ivarName>
  • <object> : 需要為成員變量設置 watchpoint 的對象。id類型
  • <ivarName> : 成員變量的名字,注意一般屬性對應的成員變量帶有 _ 前綴

e.g: 為self.subView設置watchpoint

Objective-C

(lldb) wivar self _subView
Remember to delete the watchpoint using: watchpoint delete 1
(lldb) wivarself _subView
Remember todeletethewatchpoint using: watchpoint delete 1

這時候,_subView值改變就會中斷程序

bmessage

根據方法名設置斷點

語法:

Objective-C

Syntax: bmessage <expression>
Syntax: bmessage <expression>
  • <expression> : 設置斷點的方法名,如: -[MyView setFrame:] , +[MyView awesomeClassMethod] , -[0xabcd1234 setFrame:] 等

說明:一般設置斷點,如果這個方法本類沒有實現,是父類實現的,斷點是無效的。 bmessage 有效避免了這種缺陷,即使本類沒有實現,也能設置上斷點

e.g: 給self中的 btnAction: 方法設置一個斷點

Objective-C

(lldb) bmessage -[self btnAction:]
Setting a breakpoint at -[ViewController btnAction:] with condition (void*)(id)$rdi == 0x00007ff2485311e0
Breakpoint 4: where = TLLDB`-[ViewController btnAction:] at ViewController.m:42, address = 0x000000010c4bb620
(lldb) bmessage -[self btnAction:]
Setting a breakpointat -[ViewController btnAction:]with condition (void*)(id)$rdi == 0x00007ff2485311e0
Breakpoint 4: where = TLLDB`-[ViewController btnAction:]at ViewController.m:42, address = 0x000000010c4bb620

binside

通過一個相對地址,給framework(library)設置斷點

語法:

Objective-C

Syntax: binside <address>
Syntax: binside <address>
  • <address> : framework的相對地址

pinvocation

打印方法調用堆棧,僅支持x86

語法:

Objective-C

Syntax: pinvocation [--all]
Syntax: pinvocation [--all]
  • --all / -a : 表示打印所有堆棧,不設置默認只打印當前堆棧

說明:與 bt 命令類似,不過信息比 bt 打印得更詳細,遺憾的是只能支持x86

e.g: 打印一下當前堆棧

Objective-C

(lldb) pinvocation
frame #0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28
NSInvocation: 0x7bf433e0
self: 0x7bf2d9c0
(lldb) pinvocation
frame #0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28
NSInvocation: 0x7bf433e0
self: 0x7bf2d9c0

打印所有堆棧:

Objective-C

(lldb) pinvocation -a
frame #0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28
NSInvocation: 0x7d2bb050
self: 0x7bf2d9c0
---------------------------------
frame #1: 0x008062ae UIKit`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44
NSInvocation: 0x7be18a50
self: 0x7bf2d9c0
---------------------------------
frame #2: 0x0080adce UIKit`-[UIViewController loadViewIfRequired] + 1384
NSInvocation: 0x7bf0cc40
self: 0x7bf2d9c0
---------------------------------
frame #3: 0x008569f9 UIKit`-[UINavigationController _layoutViewController:] + 52
NSInvocation: 0x7d340c90
self: 0x7c89ee00

Argument:
0xbff69108, address of @} 0x7bf2d9c0
---------------------------------
frame #4: 0x008572b1 UIKit`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 421
NSInvocation: 0x7d340cc0
self: 0x7c89ee00

2 Arguments:
0xbff69158, address of @} 0x0
0xbff6915c, address of @} 0x7bf2d9c0
---------------------------------
frame #5: 0x00857458 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 145
NSInvocation: 0x7bf24870
self: 0x7c89ee00

3 Arguments:
0xbff69298, address of i} 0
0xbff6929c, address of @} 0x0
0xbff692a0, address of @} 0x7bf2d9c0
---------------------------------
frame #6: 0x00858854 UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 1038
NSInvocation: 0x7bf16b50
self: 0x7c89ee00

Argument:
0xbff692f8, address of @} 0x0
---------------------------------
frame #7: 0x00859ada UIKit`-[UINavigationController __viewWillLayoutSubviews] + 68
NSInvocation: 0x7be18930
self: 0x7c89ee00
---------------------------------
frame #8: 0x00a35c4a UIKit`-[UILayoutContainerView layoutSubviews] + 252
NSInvocation: 0x7bf26ab0
self: 0x7bf40d40
---------------------------------
frame #9: 0x0070b008 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 810
NSInvocation: 0x7bf25da0
self: 0x7bf40d40

Argument:
0xbff693b8, address of @} 0x7bf40f80
---------------------------------
frame #10: 0x01b23059 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70
NSInvocation: 0x7d2bb6c0
self: 0x7bf40d40

2 Arguments:
0xbff693d8, address of :} layoutSublayersOfLayer:
0xbff693dc, address of @} 0x7bf40f80
---------------------------------
frame #11: 0x0496b80a QuartzCore`-[CALayer layoutSublayers] + 144
NSInvocation: 0x7bf134c0
self: 0x7bf40f80
---------------------------------
frame #12: 0x0495f4ee QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 388
---------------------------------
frame #13: 0x0495f352 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 26
---------------------------------
frame #14: 0x04951e8b QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 317
---------------------------------
frame #15: 0x04985e03 QuartzCore`CA::Transaction::commit() + 561
---------------------------------
frame #16: 0x049866c4 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
---------------------------------
frame #17: 0x01f66ffe CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
---------------------------------
frame #18: 0x01f66f5e CoreFoundation`__CFRunLoopDoObservers + 398
---------------------------------
frame #19: 0x01f5c108 CoreFoundation`CFRunLoopRunSpecific + 504
---------------------------------
frame #20: 0x01f5befb CoreFoundation`CFRunLoopRunInMode + 123
---------------------------------
frame #21: 0x00639206 UIKit`-[UIApplication _run] + 540
NSInvocation: 0x7d21fc00
self: 0x7d30bfe0
---------------------------------
frame #22: 0x0063ebfa UIKit`UIApplicationMain + 160
---------------------------------
frame #23: 0x00096a0a TMasonry`main(argc=1, argv=0xbff6a898) + 138 at main.m:14
---------------------------------
frame #24: 0x031caa21 libdyld.dylib`start + 1
---------------------------------
(lldb) pinvocation -a
frame #0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28
NSInvocation: 0x7d2bb050
self: 0x7bf2d9c0
---------------------------------
frame #1: 0x008062ae UIKit`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44
NSInvocation: 0x7be18a50
self: 0x7bf2d9c0
---------------------------------
frame #2: 0x0080adce UIKit`-[UIViewController loadViewIfRequired] + 1384
NSInvocation: 0x7bf0cc40
self: 0x7bf2d9c0
---------------------------------
frame #3: 0x008569f9 UIKit`-[UINavigationController _layoutViewController:] + 52
NSInvocation: 0x7d340c90
self: 0x7c89ee00
 
Argument:
0xbff69108, addressof @} 0x7bf2d9c0
---------------------------------
frame #4: 0x008572b1 UIKit`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 421
NSInvocation: 0x7d340cc0
self: 0x7c89ee00
 
2 Arguments:
0xbff69158, addressof @} 0x0
0xbff6915c, addressof @} 0x7bf2d9c0
---------------------------------
frame #5: 0x00857458 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 145
NSInvocation: 0x7bf24870
self: 0x7c89ee00
 
3 Arguments:
0xbff69298, addressof i} 0
0xbff6929c, addressof @} 0x0
0xbff692a0, addressof @} 0x7bf2d9c0
---------------------------------
frame #6: 0x00858854 UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 1038
NSInvocation: 0x7bf16b50
self: 0x7c89ee00
 
Argument:
0xbff692f8, addressof @} 0x0
---------------------------------
frame #7: 0x00859ada UIKit`-[UINavigationController __viewWillLayoutSubviews] + 68
NSInvocation: 0x7be18930
self: 0x7c89ee00
---------------------------------
frame #8: 0x00a35c4a UIKit`-[UILayoutContainerView layoutSubviews] + 252
NSInvocation: 0x7bf26ab0
self: 0x7bf40d40
---------------------------------
frame #9: 0x0070b008 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 810
NSInvocation: 0x7bf25da0
self: 0x7bf40d40
 
Argument:
0xbff693b8, addressof @} 0x7bf40f80
---------------------------------
frame #10: 0x01b23059 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70
NSInvocation: 0x7d2bb6c0
self: 0x7bf40d40
 
2 Arguments:
0xbff693d8, address of :} layoutSublayersOfLayer:
0xbff693dc, addressof @} 0x7bf40f80
---------------------------------
frame #11: 0x0496b80a QuartzCore`-[CALayer layoutSublayers] + 144
NSInvocation: 0x7bf134c0
self: 0x7bf40f80
---------------------------------
frame #12: 0x0495f4ee QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 388
---------------------------------
frame #13: 0x0495f352 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 26
---------------------------------
frame #14: 0x04951e8b QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 317
---------------------------------
frame #15: 0x04985e03 QuartzCore`CA::Transaction::commit() + 561
---------------------------------
frame #16: 0x049866c4 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
---------------------------------
frame #17: 0x01f66ffe CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
---------------------------------
frame #18: 0x01f66f5e CoreFoundation`__CFRunLoopDoObservers + 398
---------------------------------
frame #19: 0x01f5c108 CoreFoundation`CFRunLoopRunSpecific + 504
---------------------------------
frame #20: 0x01f5befb CoreFoundation`CFRunLoopRunInMode + 123
---------------------------------
frame #21: 0x00639206 UIKit`-[UIApplication _run] + 540
NSInvocation: 0x7d21fc00
self: 0x7d30bfe0
---------------------------------
frame #22: 0x0063ebfa UIKit`UIApplicationMain + 160
---------------------------------
frame #23: 0x00096a0a TMasonry`main(argc=1, argv=0xbff6a898) + 138 at main.m:14
---------------------------------
frame #24: 0x031caa21 libdyld.dylib`start + 1
---------------------------------

Accessibility

這個模塊的命令主要利用了 UIAccessibility 相關特性,需要開啟Accessibility功能才能使用, UIAccessibility 詳細資料可以閱讀 UIAccessibility

fa11y

根據view的 accessibilityLabel 查找view

語法:

Objective-C

Syntax: fa11y <labelRegex>
Syntax: fa11y <labelRegex>
  • <labelRegex> : 需要匹配的text

說明:UILabel,UIButton的 accessibilityLabel 等于title

e.g: 我們根據顯示的文案,查找相應的控件

Objective-C

(lldb) fa11y 媽媽
(UILabel 0x176b5bd0) 媽媽叫你回家吃飯了
(lldb) fa11y 媽媽
(UILabel 0x176b5bd0) 媽媽叫你回家吃飯了

pa11y

打印view層級中所有的 accessibilityLabel

語法:

Objective-C

Syntax: pa11y <aView>
Syntax: pa11y <aView>
  • <aView> : 需要打印層級的View,UIView類型

e.g: 我們打印一下self.view層級中所有的 accessibilityLabel

Objective-C

(lldb) pa11y self.view
UIView self.view
   | (UIButton 0x176b4600) Button
   | (UILabel 0x176b5bd0) 媽媽叫你回家吃飯了
(lldb) pa11yself.view
UIView self.view
  | (UIButton 0x176b4600) Button
  | (UILabel 0x176b5bd0) 媽媽叫你回家吃飯了

End

chisel的命令就介紹到這里,東西挺多的,沒必要全部都記住,我把這個寫出來就打算當做一個文檔,以后記不起哪個命令就查一下自己的博客。

不過chisel確實是個好東西,工欲善其事,必先利其器。要想要方便的調bug,chisel絕對值得你擁有

參考

來自: http://ios.jobbole.com/83589/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!