xcode 调试lldb
Isn’t Xcode rather great? You can use breakpoints to help you see the current state of your application at a given time.
Xcode不是很好吗? 您可以使用断点来帮助您查看给定时间的应用程序当前状态。
Many programmers know and understand the po
command — but here we are going to take a deeper dive (sic) into the debugger and what we are able to do — even changing variables on the fly! Read on…
许多程序员都了解和理解po
命令-但是在这里,我们将深入探讨调试器以及我们的能力-甚至可以随时更改变量! 继续阅读...
先决条件: (Prerequisites:)
You will be expected to be aware how to make a Single View Application in Swift
您应该知道如何在Swift中制作Single View应用程序
回购 (The repo)
There is a rather basic application stored in the repo that can allow you to display the names of some people in a UITableView
. There aren’t any tricks in there, it really is a simple-me-do implementation.BUT for the tests to work you must make sure that `Peeps.json` is visible to the test target (i.e. is a member of the test target).
有存储在一个相当基本的应用程序回购 ,可以让你在显示一些人的名字UITableView
。 那里没有任何技巧,它确实是一个简单的实现。要使测试正常运行,必须确保“ Peeps.json”对测试目标可见(即是测试的成员)目标)。
基本宝 (Basic po)
po
= Print object description
po
=打印对象描述
In my rather simple project I’ve decided to set a breakpoint on the let cell = …
line
在我相当简单的项目中,我决定在let cell = …
行上设置一个断点
![Image for post](https://miro.medium.com/max/9999/1*ltUFSZ2Ar9k8ohAhFMnEKw.png)
that gives us a project that provides us a blank screen on the simulator, but also gives us access to lldb
in the debug area (highlighted in red below):
这为我们提供了一个项目,该项目为我们提供了模拟器上的空白屏幕,还使我们可以访问调试区域中的lldb
(下面以红色突出显示):
![Image for post](https://miro.medium.com/max/9999/1*_wyj1_fILZoBHrhm2AiYjg.png)
Typing po indexPath
here provides us with a textual representation of indexPath — in this case the first indexPath
在此处输入po indexPath
可为我们提供po indexPath
的文本表示形式-在本例中为第一个indexPath
▿ 2 elements- 0 : 0- 1 : 0
Now the tableView will be populated from the people array, which is an array of struct
.
现在,将从人员数组( struct
的数组)填充tableView。
Typing po people[indexPath.row]
gives us a textual representation of the PeopleModel
that would
输入po people[indexPath.row]
为我们提供了PeopleModel
的文本表示,
▿ PeopleModel- name : "Donald J Trump"▿ job : 1 element▿ 0 : Job- role : "President"- industry : "Politics"
of an instance of the PeopleModel
type.
PeopleModel
类型的实例的实例。
We can make this a **little** easier to read by conforming to the CustomDebugStringConvertable
protocol in our PeopleModel
struct
.
我们可以使这个** ** 一点更容易符合阅读CustomDebugStringConvertable
在我们的协议PeopleModel
struct
。
![Image for post](https://miro.medium.com/max/9999/1*Tj8RjTYZ5L6Q2m4cg_7ZDA.png)
Now instead of seeing the name of the type at the top of the output, we see the name of the person (in this case “Donald J Trump” at the top.)
现在,我们没有在输出的顶部看到类型的名称,而是看到人的名字(在本例中,是“ Donald J Trump”在顶部)。
▿ Donald J Trump- name : "Donald J Trump"▿ job : 1 element▿ 0 : Job- role : "President"- industry : "Politics"
But po
(print object description) can do more than just that. We can perform computations on the People
Array — perhaps view the last element in the array through po people.last
, the first person’s name po people.first?.name
or a host of other Swift functions.
但是po
(打印对象描述)不仅可以做更多的事情。 我们可以在People
数组上执行计算-也许通过po people.last
,第一人称名字po people.first?.name
或其他许多Swift函数查看数组中的最后一个元素。
表达 (expression)
po
itself is an alias for expression, which when passed — object-description
functions in exactly the same way as po
.
po
本身是表达式的别名,该别名在传递时— object-description
功能与po
完全相同。
Print out the complete people array: expression — object-description — people
打印出完整的人员数组: expression — object-description — people
创建自己的命令allias (create your own command allias)
This can be done with command alias
followed by your new alias, completed by the expression.
这可以通过command alias
后跟您的新别名(由表达式完成)来完成。
However, these do not persist over mutliple sessions.
但是,这些不会在多个会话中持续存在。
基本p (Basic p)
p
= Print
p
=打印
You might get some unexpected results if you use po
on things that aren’t objects (for example NSNumber
instances)
如果在非对象上使用po
(例如NSNumber
实例),则可能会得到一些意外的结果
Once again (with the breakpoint in the same place, Typing p people[indexPath.row]
gives us a textual representation of the PeopleModel
, but with different formatting.
再次(在同一位置使用断点,键入p people[indexPath.row]
为我们提供了PeopleModel
的文本表示形式,但格式不同。
(lldb.PeopleModel) $R2 = {name = "Donald J Trump"job = 1 value {[0] = (role = "President", industry = "Politics")}}
This can later be referred to as $R2
in lldb (so p $R2
will give the same result as above, and p $R2.name
)
以后可以在lldb中将其称为$R2
(因此p $R2
将提供与上述相同的结果,而p $R2.name
)
You may also see the non-human readable format by using expression — raw
that is, expression — raw — people[indexPath.row]
. This raw print gives a nightmare printout as follows:
通过使用expression — raw
即expression — raw — people[indexPath.row]
,您可能还会看到非人类可读的格式。 该原始打印内容将进行噩梦打印,如下所示:
(lldb.PeopleModel) $R2 = {name = {_guts = {_object = {_countAndFlagsBits = {_value = -4611686018427387890}_object = 0x4000600001fd2e00}}}job = {_buffer = {_storage = {rawValue = 0x0000600000ad4440 {Swift.__ContiguousArrayStorageBase = {Swift.__SwiftNativeNSArrayWithContiguousStorage = {Swift.__SwiftNativeNSArray = {}}countAndCapacity = {_storage = {count = {_value = 1}_capacityAndFlags = {_value = 2}}}}}}}}}
The human readable formatter works for many types when using p
— unless you are using raw
this makes things much easier to understand and to read (that being the point in human readable output, you know!)
当使用p
时,人类可读格式器适用于许多类型-除非您使用raw
否则它使事情更易于理解和阅读(这是人类可读输出的关键!)
基本v (Basic v)
The value of a variable is read from memory, and is output using the same formatter as p
.
从内存中读取变量的值,并使用与p
相同的格式器输出。
v does not compile code — so is very fast! However computed values cannot be calculated.
v不编译代码-速度非常快! 但是,无法计算计算值。
v indexPath
v indexPath
Gives a view of the two indicies
给出两个指标的视图
In this implementation v self.people
will not resolve, as people is a lazy var
(feel free to play with the implementation to see how else you can frame this, and what else you can do).
在此实现中, self.people
将无法解析,因为people是一个lazy var
(随意使用该实现,以了解可以如何构造此框架以及可以做什么)。
差异 (The differences)
Dynamic type resolution means that v
can be very useful in some individual cases when using lldb
.
动态类型解析意味着v
在使用lldb
某些情况下可能非常有用。
![Image for post](https://miro.medium.com/max/9999/1*76K3VgQA3q7aJUEOqn_ReA.png)
动态跟踪UITableView中的数据 (Dynamically chaging the data in the UITableView)
This is it!
就是这个!
As we have seen above, we can use expression
in lldb.
如上所述,我们可以在lldb中使用expression
。
Now if we put a breakpoint on line 41 like:
现在,如果我们在第41行放置一个断点,例如:
![Image for post](https://miro.medium.com/max/9999/1*VO9T918U0gLIn21tIkAdUw.png)
we can wait for the first time the breakpoint is hit, and type the following in lldb
我们可以等待第一次遇到断点,然后在lldb中键入以下内容
expression cell.textLabel?.text = “test”
expression cell.textLabel?.text = “test”
![Image for post](https://miro.medium.com/max/9999/1*pdHjWKW65ORxIQBwb89bYg.png)
breakpoint disable
as a command gets rid of the breakpoint (you might click on the breakpoint to disable it), and then continue with ⌃ + ⌘ + Y
breakpoint disable
作为命令摆脱了断点(您可以单击断点以将其禁用),然后继续执行⌃ + ⌘ + Y
![Image for post](https://miro.medium.com/max/9999/1*W3-FD45lcAgHDmcyOFAVDQ.png)
The first line of the UITableView
is now displaying test! As expected (this is what I expected, what did you expect?)
UITableView
的第一行现在显示测试! 符合预期(这是我所期望的,您期望什么?)
动态自动更改数据 (Dynamically automatically change the data)
We can add a debugger command to the breakpoint.
我们可以将调试器命令添加到断点。
A right-click on the breakpoint gives some wonderful opportunities. Now if we choose a Debugger Command
for the same code, that is expression cell.textLabel?.text = “test”
and make sure it only happens for the execution where indexPath.row == 0
在断点上单击鼠标右键会提供一些绝佳的机会。 现在,如果我们为相同的代码选择一个Debugger Command
,即expression cell.textLabel?.text = “test”
,并确保它仅在indexPath.row == 0
的执行中发生。
![Image for post](https://miro.medium.com/max/9999/1*RsfdNnIESmB-y5_HvyJvAQ.png)
Note that I also ticked the box to automatically continue — stopping me having to press the annoyong ⌃ + ⌘ + Y
keyboard combination.
请注意,我也勾选了该框以自动继续-停止我必须按annoyong ⌃ + ⌘ + Y
键盘组合。
如果您可以对视觉元素做同样的事情怎么办? (What if you can do the same for visual elements?)
Here I’ve created a simple view with a `UILabel` that will be clipped. You might get some feedback from a user that the label is clipped — this is unacceptable!
在这里,我创建了一个带有UILabel的简单视图,该视图将被裁剪。 您可能会从用户那里收到一些标签被剪掉的反馈-这是不可接受的!
![Image for post](https://miro.medium.com/max/9999/1*WbsKLZvLHugBpRbNmjKOHA.png)
Once the application is run, you can go to xCode and press the button highlighted with a red box below:
运行该应用程序后,您可以转到xCode并按下面带有红色框突出显示的按钮:
![Image for post](https://miro.medium.com/max/9999/1*09jUebrv3DHuLVKXafDahg.png)
We enter the visual debugger, and we can see that the label is clipped (well, we knew that!). Here we are trying to identify the clipped image — and there is button we can press to show views that have been clipped (highlighted in red below):
我们进入可视调试器,可以看到标签被裁剪了(嗯,我们知道!)。 在这里,我们试图识别被剪切的图像,并且可以按下按钮以显示已被剪切的视图(下面以红色突出显示):
![Image for post](https://miro.medium.com/max/9999/1*pVEWPfphU8OnHFDpU2H-9Q.png)
the button next to that is constraint mode, and we can see all of the constraints in operation at this point in time.
旁边的按钮是约束模式,我们可以看到此时所有正在运行的约束。
Now you can click on any element on the left-hand side, right-click and print description. If you print descriptions of the constraints, it becomes obvious that one of the constraints of the label is wrong. In my case, this is the following:
现在,您可以单击左侧的任何元素,右键单击并打印说明。 如果您打印约束的描述,很明显标签的约束之一是错误的。 就我而言,这是以下内容:
Printing description of $16:<NSLayoutConstraint:0x6000038ca120 UILayoutGuide:0x600002296060'UIViewSafeAreaLayoutGuide'.trailing == UILabel:0x7f9b5b4185f0'This is a test label that...'.trailing - 30 (active)>
now we can find this constraint, and then cast it to NSLayoutConstraint
in order to po
现在,我们可以找到这个约束,然后将其转换为NSLayoutConstraint
以po
po ((NSLayoutConstraint *)0x6000038ca120)
po ((NSLayoutConstraint *)0x6000038ca120)
which displays
显示
<NSLayoutConstraint:0x6000038ca120 UILayoutGuide:0x600002296060'UIViewSafeAreaLayoutGuide'.trailing == UILabel:0x7f9b5b4185f0'This is a test label that...'.trailing - 30 (active)>
now I want this trailing — 30
to become a trailing + 30
现在我希望这条trailing — 30
变成trailing + 30
so we can set that with
所以我们可以用
expression [((NSLayoutConstraint *)0x6000038ca120) setConstant:30]
expression [((NSLayoutConstraint *)0x6000038ca120) setConstant:30]
I want to update the paused application with the following expression
我想用以下表达式更新暂停的应用程序
expression -l objc — (void)[CATransaction flush]
expression -l objc — (void)[CATransaction flush]
and then the simulator (or your device) shows the changes!! CAN.
然后模拟器(或您的设备)显示更改!! 能够。
![Image for post](https://miro.medium.com/max/9999/1*OdAKXwm2lxnECCDSceJ-Ow.png)
Andddddd. We’re done.
安德 大功告成
结论 (Conclusion)
Like anything in programming, using different tools is important depending on the context — you might use p
, po
or v
depending on what you want to acheive and how you want to manipulate data.
像编程中的所有内容一样,根据上下文使用不同的工具也很重要-您可以根据要实现的目标以及如何操作数据来使用p
, po
或v
。
I hope this short article has given you some ideas on how you can use these features of lldb
and how you can think about using this tool to write better code!
希望这篇简短的文章为您提供一些有关如何使用lldb
这些功能以及如何考虑使用此工具编写更好的代码的想法!
By dynamically changing code while it is running you can change things while the code is running — cutting down on the amount of time you need to spend running and rerunning code. Saving you time? What an article!
通过在代码运行时动态更改代码,您可以在代码运行时进行更改,从而减少了花在运行和重新运行代码上的时间。 节省您的时间? 真是一篇文章!
I hope this article has been of help to you, and you can see the code from this is included in the attached Repo to get the whole lot in one go!
希望本文对您有所帮助,并且您可以在随附的Repo中查看其中的代码,以便一次性获得全部信息!
If you’ve any questions, comments or suggestions please hit me up on Twitter
如果您有任何疑问,意见或建议,请在Twitter上打我
翻译自: https://medium.com/@stevenpcurtis.sc/use-lldb-to-dynamically-change-code-in-xcode-4eae758cdc03
xcode 调试lldb