转自:https://www.leewong.cn/2020/07/25/howtousexcodebreakpoint/
image上图是我们使用Xcode进行断点调试时,上图底部图标从左到右功能分别如下:
- 启用/禁用断点(点击后变灰色,所有断点失效;再点击变蓝色,所有断点生效)
- 继续执行程序(点击后跳过本次断点,继续执行程序)
- 执行下一步(点击后执行第23行代码)
- 进入方法(点击后进入-testLog方法)
- 跳出方法(在-testLog方法内部点击后回到第22行代码)
除了这些功能,我们还可以编辑断点,在断点出右键选择Edit BreakPoint
下面我们来分别介绍下这几个选项以及如何设置这些选项:
Condition
Condition
表示断点条件。开发者可以在 Condition
输入框中设置触发断点的条件。比如上面 for 循环的例子我们可以在 Condition
条件中添加条件
这样我们的断点只有在index==5
时才会被触发,这样就有利于我们在某些for循环时只有在满足某个条件时才触发断点。
Ignore
Ignore
为忽略次数,同样我们在上面for循环的例子中可以将Ignore
设置为5,那么断点第一次触发时index=6时。
Action
Action为触发动作。Action可以添加多条,在触发断点后,会紧接着执行设定的Actions。Action有6种执行类型,其中较常用的有Debugger Command和Log message。
Debugger Command
image imageLog Message
image image当然log的信息还可以读出来
image试一下吧,有惊喜!!!
Options
Options
控制在执行断点对应的Actions
后是否自动继续执行程序。勾选后Options
后,断点被触发后不进入Debug
界面。
接下来看下断点的正题
断点
断点类型
我们在Xocde中添加断点时有几种类型的断点:
image下面介绍下常用的几种类型的断点:
Exception Breakpoint(异常断点)
当我们添加了一个Exception BreakPoint
时,实际上是添加了一个全局断点
正常情况下我们的代码崩溃后,如果没有全局断点 代码会崩溃在main函数中,但是我们如果添加了全局断点,代码发生崩溃时,就会自动崩溃到出现问题的哪一行代码,比较方便我们去定位问题。
Symbolic Breakpoint (符号断点)
当我们添加一个符号断点时,会自动为我们弹出自定义面板,
image与普通断点相比,符号断点的编辑界面多出来Symbol和Module两个输入框。下面我们来看下这两个输入框的作用。
Symbol
可以在Symbol输入框中设置断点触发方法/函数。在Symbol中设置一个方法/函数后,运行程序并执行到此方法时会触发断点。
image如果是C语言方法那么直接使用方法名就可以
imageModule
可以在Module输入框中设置Symbol中的函数所在的库,以避免不同库中存在名字相同的方法/函数,默认不用填写。
Condition
与普通断点的用法基本一致
在Condition输入框中设置$arg3==nil
,就会限制断点在满足第一个参数和第二个参数都为nil时才会被触发。但是实际上使用下面这种写法才可以
[(NSString *)$arg3 length] == 0
这里我们可以用来判断某个方法再被调用时,哪里的参数传递是有问题的。
Watch Breakpoint(监控断点)
有时候我们需要监听某个变量的值的变化
image断点结果
image
很可惜没有发现监听数组个数变化的断点
断点的应用
查看UI控件约束冲突
我们先看下下面这段代码:
- (void)addVCSubView {
UIView *contentView = [[UIView alloc] init];
contentView.backgroundColor = [UIColor blueColor];
[self.view addSubview:contentView];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.width.height.equalTo(@200);
}];
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor greenColor];
[contentView addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(contentView);
make.centerY.equalTo(contentView);
make.top.equalTo(contentView.mas_top).offset(20);
make.width.height.equalTo(@100);
}];
}
- (void)addVCSubView { UIView *contentView = [[UIView alloc] init]; contentView.backgroundColor = [UIColor blueColor]; [self.view addSubview:contentView]; [contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.view); make.width.height.equalTo(@200); }]; UIView *view = [[UIView alloc] init]; view.backgroundColor = [UIColor greenColor]; [contentView addSubview:view]; [view mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(contentView); make.centerY.equalTo(contentView); make.top.equalTo(contentView.mas_top).offset(20); make.width.height.equalTo(@100); }];}
image
从图中我们可以很明显的看到绿色的子视图的宽高并不相同,同样在控制台上我们也看到了这样的输出
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<MASLayoutConstraint:0x600000e183c0 UIView:0x7fa513e11cc0.height == 200>",
"<MASLayoutConstraint:0x600000e181e0 UIView:0x7fa516604e70.centerY == UIView:0x7fa513e11cc0.centerY>",
"<MASLayoutConstraint:0x600000e18600 UIView:0x7fa516604e70.top == UIView:0x7fa513e11cc0.top + 20>",
"<MASLayoutConstraint:0x600000e186c0 UIView:0x7fa516604e70.height == 100>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x600000e186c0 UIView:0x7fa516604e70.height == 100>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
控制台提示我们 下面列表中的约束其中有一个是不需要的,同时当前展示的样子是系统通过移除了哪个约束后展示出来的
约束问题是什么
我们先看下控制台输出的提示
"<MASLayoutConstraint:0x600000e183c0 UIView:0x7fa513e11cc0.height == 200>",
"<MASLayoutConstraint:0x600000e181e0 UIView:0x7fa516604e70.centerY == UIView:0x7fa513e11cc0.centerY>",
"<MASLayoutConstraint:0x600000e18600 UIView:0x7fa516604e70.top == UIView:0x7fa513e11cc0.top + 20>",
"<MASLayoutConstraint:0x600000e186c0 UIView:0x7fa516604e70.height == 100>"
上面的提示中设计到两个UIView对象,0x600000e183c0
和0x7fa513e11cc0
,通过查看上面的约束提示,我们发现height
,centerY
,top
,height
这几个约束都是垂直方向的约束。
上面的提示还有下面这句
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x600000e186c0 UIView:0x7fa516604e70.height == 100>
尝试通过break高度为100的约束来正确展示这个视图,而结合我们上面展示的图片 没有生效的约束是height=100
与上面的描述一致。
那通过上面的分析我们得出这次约束的问题是:
控件0x600000e183c0
和0x7fa516604e70
在垂直方向存在约束冲突,目前系统通过移除UIView:0x7fa516604e70.height == 100
约束来展示UI,如果系统的修改与你的预期不符,可以通过修改上面提到的四个约束中的一个来展示出正确的UI。
哪个视图约束有问题
分析出约束的问题后,我们需要定位到底是哪两个视图出现了约束问题。
通过内存地址定位
我们可以通过查看层次结果,然后通过出现约束问题的视图的内存地址进行筛选,这样我们就能容易的定位到出现问题的视图。
image通过lldb命令
我们还可以通过设置出现问题的视图的背景颜色来定位到底是哪个视图出现问题,当然是用lldb命令的前提是我们需要在合适的地方添加断点。
首先我们需要在项目中添加约束冲突(符号断点)断点,添加方法如下
image添加了这个断点后,在应用启动遇到约束冲突的位置系统会,直接有约束冲突的位置设置断点,下面截取一部分发生断点时的提示
*UIButton:0x10b091670'注册/登录'- AMBIGUOUS LAYOUT for UIButton:0x10b091670'注册/登录'.minY{id: 159} UIButtonLabel:0x10b15fb60'注册/登录'
*UILabel:0x10b08f790'群组'- AMBIGUOUS LAYOUT for UILabel:0x10b08f790'群组'.minX{id: 136}, UILabel:0x10b08f790'群组'.minY{id: 138}, UILabel:0x10b08f790'群组'.Width{id: 135}, UILabel:0x10b08f790'群组'.Height{id: 140}
这里我们可以通过关键词 AMBIGUOUS LAYOUT
来获取所有存在约束冲突的位置,因为log中有了按钮或者label的文案我们可以很快的定位到具体位置。
当然 如果层次非常深,或者我们无法通过文案进行区分,我们还可以通过下面的命令修改视图的背景颜色来定位出现约束冲突的视图。
expr ((UILabel *)0x10b091670).backgroundColor = [UIColor yellowColor];
结果如下图:
image通过上面的方法我们可以定位到出现问题的视图控件,那么我们 下一步就要看如何去解决这个约束冲突。
网友评论