打印和赋值,观察数值变量和view对象属性

  • p指令可打印其对象类型、内存地址以及该对象的值等具体信息,
  • po指令则是打印其调用description方法得到的值。
  • e 赋值指令(后面有例子详解)

流程控制

n 命令,代表 Step Over 操作。

s 命令,代表 Step Into 操作。

finish 命令,代表 Step Out 操作。

c 命令,代表恢复程序执行操作。

修改指针变量的值,观测程序不同变化

程序中: testThreadReturn = “testThreadReturn”

(lldb) p testThreadReturn
(String) $R2 = "testTheardReturn"
(lldb) e testThreadReturn = "zaozuo"
(lldb) p testThreadReturn
(String) $R4 = "zaozuo"

动态修改view的属性

Thread Return,函数设置断点返回值(swift不兼容)

  • 这个在OC一切ok,在swift还不能用会有以下错误
(lldb) thread return "zaozuo-return"
error: Error returning from frame 0 of thread 1: We only support setting simple integer and float return types at present..

调试时,还有一个很棒的函数可以用来控制程序流程:thread return 。它有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,然后立刻执行返回命令,跳出当前栈帧。这意味这函数剩余的部分不会被执行。这会给 ARC 的引用计数造成一些问题,或者会使函数内的清理部分失效。但是在函数的开头执行这个命令,是个非常好的隔离这个函数,伪造返回值的方式 。

直接设置返回值,不用写死代码破坏代码结构

(五星推荐):编辑断点

设置断点进入条件,condition

断点行为 (Action):

可以设置或不设置,断点进入的条件,设置进入条件后还可以,自定义后续的动作,比如,打印值,修改值,执行shell命令,执行lldb命令,打印log等等很多自定义的动作,这一点确实很强大,这里就可以和shell 脚本联动,测试一些不好测试的点,和需要提前处理外部因素的案例

(五星推荐):在lldb中初始化值,动态赋值,执行多行语句

  • 简单变量赋值,仅仅在调试环境赋值了一个值,是局部变量,可以用print打印
(lldb) e let hello = "Hello"
you can simply use:
(lldb) p let hello = "Hello"
  • 使用"$"符号定义全局常量和变量
OC中为:
(lldb) e NSString *$a = @"c" (lldb) po $a c Swift中变为:
(lldb) e let $a = "a"
(lldb) po $a "a"
  • Swift中多行语句:输入完成敲一个空行即可开始执行
(lldb) p
Enter expressions, then terminate with an empty line to evaluate:
struct compass{var direction = "N"; var angle = 16.5}
var c = compass()
print(c)
(lldb)
  • 同样的你也可以向当前view添加一个layer
(lldb) p
Enter expressions, then terminate with an empty line to evaluate:
1 let layer = CALayer()
2 layer.backgroundColor = UIColor.yellow.cgColor
3 layer.bounds = CGRect(x:0, y:0, width:100, height:100)
4 layer.position = CGPoint(x:250, y:300)
5 layer.cornerRadius = 12.0
6 view.layer.addSublayer(layer)
7
(lldb)

  • 修改函数中成员变量的值

引入模块 Importing modules

(lldb) p import MapKit

打印UI层级关系及更新UI

  • oc,试了下这个在swift也可以运行:
(lldb) po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
<UIWindow: 0x7ffcd2f0f1e0; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7ffcd2f10170>; layer = <UIWindowLayer: 0x7ffcd2f0ea80>>
| <UIView: 0x7ffcd2c6dc10; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7ffcd2c17f10>>
| | <UIButton: 0x7ffcd2c6dfc0; frame = (20 62; 78 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7ffcd2c6bc10>>
| | | <UIButtonLabel: 0x7ffcd2f15af0; frame = (16 6; 46 18); text = 'Button'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7ffcd2f16120>>
| | <_UILayoutGuide: 0x7ffcd2c6fae0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7ffcd2c6faa0>>
| | <_UILayoutGuide: 0x7ffcd2c70740; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x7ffcd2c6d3d0>>
  • swift:
expr -l objc++ -O -- [[[UIWindow keyWindow] rootViewController] _printHierarchy]
  • view指针赋值
(lldb) e id $view = (id) 0x7fbd71432590
  • 使用指针进行操作
(lldb) e (void) [$view setBackgroundColor:[UIColor redColor]]
  • 当然,我们运行完这条命令,界面上不会马上反应出来,我们还需要

    调用这个命令刷新一下:
(lldb) e (void)[CATransaction flush]

Push 一个 View Controller

  • 第一步我本地实验了下没有成功,报错了就,可能我代码是swift的所以得用swift 代码,下面仅仅oc 可以
(lldb) e navigationController?.pushViewController($vcc, animated: true)
MainNavigationController.swift[36], pushViewController: [pushViewController=====><zaozuo.ProductCategoryController: 0x7ffce5147600>]
(Swift.Void?) $R4 = nil 然后执行:
(lldb) caflush // e (void)[CATransaction flush]
或是
(lldb) c
都可以

查找按钮的 target(这个方法还未尝试,留在这里开阔下思路)

想象你在调试器中有一个 $myButton 的变量,可以是创建出来的,也可以是从 UI 上抓取出来的,或者是你停止在断点时的一个局部变量。你想知道,按钮按下的时候谁会接收到按钮发出的 action。非常简单:

(lldb) po [$myButton allTargets]
{(
<MagicEventListener: 0x7fb58bd2e240>
)}
(lldb) po [$myButton actionsForTarget:(id)0x7fb58bd2e240 forControlEvent:0]
<__NSArrayM 0x7fb58bd2aa40>(
_handleTap:
)

观察实例变量的变化

假设你有一个 UIView,不知道为什么它的 _layer 实例变量被重写了 (糟糕)。因为有可能并不涉及到方法,我们不能使用符号断点。相反的,我们想监视什么时候这个地址被写入。

首先,我们需要找到 _layer 这个变量在对象上的相对位置:

(lldb) p (ptrdiff_t)ivar_getOffset((struct Ivar *)class_getInstanceVariable([MyView class], "_layer"))
(ptrdiff_t) $0 = 8
现在我们知道 ($myView + 8) 是被写入的内存地址: (lldb) watchpoint set expression -- (int *)$myView + 8
Watchpoint created: Watchpoint 3: addr = 0x7fa554231340 size = 8 state = enabled type = w
new value: 0x0000000000000000
这被以 wivar $myView _layer 加入到 Chisel 中。

非重写方法的符号断点

假设你想知道 -[MyViewController viewDidAppear:] 什么时候被调用。如果这个方法并没有在MyViewController 中实现,而是在其父类中实现的,该怎么办呢?试着设置一个断点,会出现以下结果:

(lldb) b -[MyViewController viewDidAppear:]
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.

因为 LLDB 会查找一个符号,但是实际在这个类上却找不到,所以断点也永远不会触发。你需要做的是为断点设置一个条件 [self isKindOfClass:[MyViewController class]],然后把断点放在 UIViewController 上。正常情况下这样设置一个条件可以正常工作。但是这里不会,因为我们没有父类的实现。

viewDidAppear: 是苹果实现的方法,因此没有它的符号;在方法内没有 self 。如果想在符号断点上使用 self,你必须知道它在哪里 (它可能在寄存器上,也可能在栈上;在 x86 上,你可以在 $esp+4 找到它)。但是这是很痛苦的,因为现在你必须至少知道四种体系结构 (x86,x86-64,armv7,armv64)。想象你需要花多少时间去学习命令集以及它们每一个的调用约定,然后正确的写一个在你的超类上设置断点并且条件正确的命令。

幸运的是,这个在 Chisel 被解决了。这被成为

bmessage:
(lldb) bmessage -[MyViewController viewDidAppear:]
Setting a breakpoint at -[UIViewController viewDidAppear:] with condition (void*)object_getClass((id)$rdi) == 0x000000010e2f4d28
Breakpoint 1: where = UIKit`-[UIViewController viewDidAppear:], address = 0x000000010e11533c

让代码停在Swift Error 或者Objective C异常

  • 停在Objective C异常
(lldb) br s -E  objc
Breakpoint 6: where = libobjc.A.dylib`objc_exception_throw, address = 0x000000010dededbb
  • 停在Swift Error
(lldb) br s -E swift
Breakpoint 7: where = libswiftCore.dylib`swift_willThrow, address = 0x000000010e55ccc0
  • 停在某一种类型的Swift Error
(lldb) br s -E swift -O EnumError
Breakpoint 8: where = libswiftCore.dylib`swift_willThrow, address = 0x000000010e55

参考

http://lldb.llvm.org/

https://lldb.llvm.org/lldb-gdb.html

https://www.invasivecode.com/weblog/lldb-expression-for-code-injection-in-xcode

http://www.theappbusiness.com/blog/debugging-in-swift

iOS 开发者旅途中的指南针 - LLDB 调试技术,swiftcafe

与调试器共舞 - LLDB 的华尔兹

Chisel-LLDB命令插件,让调试更Easy

Chisel常用命令总结

Swift 代码调试核武-LLDB调试基础

Basic LLDB tips

udacity 的视频教程

结尾

LLDB 调试命令强大,但是有些语法不大好书写,Chisel 做了封装和一些扩展,使得调试App 不在打印各种log,我们可以快捷的查看或是修改代码内的变量,常量,数组,对象,在断点位置执行log,shell等但这都是调试代码内部信息,如何更加灵活的调试UIView和约束信息呢?

这就有了下文:

Reveal 9 iOS 界面调试

Swift 使用 LLDB 调试命令的更多相关文章

  1. lldb调试命令

    XCode4.0以后,编译器换成了LLVM 编译器 2.0 与以前相比,更加强大:1.LLVM 编译器是下一带开源的编译技术.完全支持C, Objective-C, 和 C++.2.LLVM 速度比 ...

  2. xcode gdb/lldb调试命令

    命令                        解释 break NUM               在指定的行上设置断点. bt                      显示所有的调用栈帧.该 ...

  3. iOS LLDB调试器

    随着Xcode 5的发布,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器.它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.LLDB为Xcode提供了底层调试环 ...

  4. LLDB调试基本使用

    在平时开发中,我们可能需要调试某些东西,比如查看给服务器发请求时传过去的参数,如果不适用LLDB的话我们用的最多的就是通过NSLog方式去打印,但现在我们可以精简这个步骤,那就是使用LLDB调试命令. ...

  5. iOS - 浅谈LLDB调试器

    摘要 LLDB是Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.平时用Xcode运行程序,实际走的都是LLDB.熟练使用LLDB,可以让你debug事半功 ...

  6. lldb调试使用python脚本问题总结

    lldb调试器可以使用python脚本实现功能增强,但也不是可以随心所欲的,在实际中有很多地方需要注意. 首先是对多线程环境调试使用python脚本,也要考虑python脚本有多线程安全,尤其是有许多 ...

  7. iOS之LLDB常用调试命令

    LLDB是个开源的内置于XCode的调试工具,这里来理一理常用用法.lldb对于命令的简称,是头部匹配方式,只要不混淆,你可以随意简称某个命令.结果为在xcode下验证所得,可能与其它平台有所误差. ...

  8. iOS 开发者旅途中的指南针 - LLDB 调试技术

    文章转载于:iOS 开发者旅途中的指南针 - LLDB 调试技术 今天给大家介绍的内容,无关乎任何功能性开发技术,但又对开发的效率影响至深,这就是调试技术. 何为调试呢,比如我们用 print 函数在 ...

  9. LLDB调试详解--逆向开发

    前言 今天讲述在苹果日常开发中一个装逼神器LLDB,是Xcode内置的动态调试工具. 在iOS系统程序开发中,会经常需要代码调试的追踪, 最常用的也是LLDB(low level debugger) ...

随机推荐

  1. Ruby 面向对象知识详解

    Ruby 是纯面向对象的语言,Ruby 中的一切都是以对象的形式出现.Ruby 中的每个值都是一个对象,即使是最原始的东西:字符串.数字,甚至连 true 和 false 都是对象.类本身也是一个对象 ...

  2. mysql中如何开启binlog?开启二进制日志文件?binary log?

    需求描述: 开启mysql的binlog即binary log日志功能,在此记录下. 版本描述: mysql版本:5.7.21-log 操作过程: 1.修改my.cnf并且将以下参数加入其中,重启my ...

  3. Java获取一维数组的最小值

    编写程序,实现接受用户在文本框中输入的单行数据.这些数据都是整数数字,以空格进行分隔,空格数量不限.并将这些数据分割成一维数组,再从数组中提取最小值显示在界面中.思路是先对用户的输入进行验证,即先用t ...

  4. Apache双机热备

    部署方案 1.1 方案设计 1.2 方案描述 如上图所示,我们要有三个可用的IP地址(切记不能与网络中其他机器IP重复),针对我使用的三个IP地址做如下说明: 10.16.252.10 //这个IP地 ...

  5. SpringMVC由浅入深day02_7上传图片

    7 上传图片 7.1 需求 在修改商品页面,添加上传商品图片功能. 7.2 springmvc中对多部件类型解析 在页面form中提交enctype="multipart/form-data ...

  6. 开发还是应该使用linux

    这几天在Windows系统下,安装了几个IDE,体量大,4.5个G,启动速度慢,占用系统资源多,并且最难受的是,这些IDE的限制性太强,只能按照UI给定的规则来操作,例如现在手中有一个已完成的项目,用 ...

  7. The list of pre-build cross-compiler

    Recently, I need compile toybox and busybox for my router. This is a list of cross-compiler for MIPS ...

  8. iOS开发-编译出错 duplicate symbols for architecture x86_64

    今天对原来项目文件进行重新整理,根据文件内容进行分类,结果复制粘贴时没注意把一个文件复制了两遍 编译的时候就出现Duplicate Symbol Error 在网上搜素了一圈发现也有人遇到过这个问题, ...

  9. Selenium 节点交互

    Selenium 可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作 常见方法:输入文字时用 send_keys() 方法,清空文字时用 clear() 方法,点击按钮时用 click ...

  10. [Ubuntu] 如何设置静态 IP 和 DNS

    编辑 /etc/network/interfaces 来设置 IP 和 DNS 解析服务器: # interfaces() ) and ifdown() auto lo iface lo inet l ...