热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Swift使用LLDB调试命令

swift和oc的语法不一样:Xcode调试技巧之Swift篇打印和赋值,观察数值变量和view对象属性p指令可打印其对象类型、内存地址以及该对象的值等具体信息,po指令则是打印其

  • swift 和 oc 的语法不一样:
    Xcode 调试技巧之 Swift 篇

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

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

流程控制

Swift 使用 LLDB 调试命令

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的属性

Swift 使用 LLDB 调试命令

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

Swift 使用 LLDB 调试命令

断点行为 (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)

Swift 使用 LLDB 调试命令

  • 修改函数中成员变量的值
    Swift 使用 LLDB 调试命令

引入模块 Importing modules

(lldb) p import MapKit

打印UI层级关系及更新UI

  • oc,试了下这个在swift也可以运行:
(lldb) po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
; layer = >
   | >
   |    | >
   |    |    | >
   |    | <_UILayoutGuide: 0x7ffcd2c6fae0; frame = (0 0; 0 20); hidden = YES; layer = >
   |    | <_UILayoutGuide: 0x7ffcd2c70740; frame = (0 667; 0 0); hidden = YES; layer = >
  • 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=====>]
(Swift.Void?) $R4 = nil

然后执行:
(lldb) caflush // e (void)[CATransaction flush]
或是
(lldb) c
都可以

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

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

(lldb) po [$myButton allTargets]
{(
    
)}
(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 界面调试


推荐阅读
  • Yii framwork 应用小窍门
    Yiiframework应用小窍门1.YiiFramework]如何获取当前controller的名称?下面语句就可以获取当前控制器的名称了!Php代码 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 微软评估和规划(MAP)的工具包介绍及应用实验手册
    本文介绍了微软评估和规划(MAP)的工具包,该工具包是一个无代理工具,旨在简化和精简通过网络范围内的自动发现和评估IT基础设施在多个方案规划进程。工具包支持库存和使用用于SQL Server和Windows Server迁移评估,以及评估服务器的信息最广泛使用微软的技术。此外,工具包还提供了服务器虚拟化方案,以帮助识别未被充分利用的资源和硬件需要成功巩固服务器使用微软的Hyper - V技术规格。 ... [详细]
  • 本文详细介绍了在Linux虚拟化部署中进行VLAN配置的方法。首先要确认Linux系统内核是否已经支持VLAN功能,然后配置物理网卡、子网卡和虚拟VLAN网卡的关系。接着介绍了在Linux配置VLAN Trunk的步骤,包括将物理网卡添加到VLAN、检查添加的VLAN虚拟网卡信息以及重启网络服务等。最后,通过验证连通性来确认配置是否成功。 ... [详细]
  • Iwanttointegratesort,order,maxandoffsetinafindAllquery.Thefollowingworksfine:我想在fin ... [详细]
author-avatar
dmcm0007
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有