Xcode Debug调试汇总

7,342 阅读4分钟

未完待续,[继续总结]

LLDB && GDB

lldb与gdb命令对比

常用的Debug快捷键

功能 命令
暂停/继续 cmd + ctrl + Y
断点失效/生效 cmd + Y
控制台显示/隐藏 cmd + shift + Y
光标切换到控制台 cmd + shift + C
清空控制台 cmd + K
step over F6
step into F7
step out F8

技巧一:格式化输出数据

1、封装log函数
//swift版
func DLog<T>(message: T, file: String = #file, method: String = #function, line: Int = #line) { 
    #if DEBUG 
        print("<\((file as NSString).lastPathComponent) : \(line)>, \(method)  \(message)")
    #endif
}

//OC版
#ifdef DEBUG
	 #define DLog(fmt, ...) NSLog((@"<%s : %d> %s  " fmt), [[[NSString stringWithUTF8String:__FILE__] lastPathComponent]   UTF8String], __LINE__, __PRETTY_FUNCTION__,  ##__VA_ARGS__);
#else
	#define DLog(...)
#endif
2、代替NSLog,打印对象的内部属性

技巧二:条件断点(condition)

设置断点触发条件

注意:

// 正确
(BOOL)[pId isEqualToString:@"short-videopage"]

// 报错:error: no known method '-isEqualToString:'; cast the message send to the method's return type
[pId isEqualToString:@"short-videopage"]

技巧三:运行中修改变量的值(expr & call)

在调试登录相关的bug时,非常方便,不用担心经常输密码,还输错的尴尬

调试UI,改变指定控件的颜色

技巧四:符号断点(Add Symbolic Breakpoint)

当我们查看一个陌生的项目的时候,我们可以先运行APP,对所有的viewDidLoad函数添加断点,进而了解代码执行路径

Symbol:符号

  • c语言,methodName只需要写函数名,不用写后面的()
  • oc样式,[className methodName] className是类名,methodName是方法名(不区分类方法和实例方法)
  • swift样式,ClassName.methodName

Module模块筛选:可以避免不同库中方法名或者函数名相同 Condition触发条件

这里可以添加一些指定触发条件,比如添加第一个参数(arg3)不能为nil。这里arg4代表第2个参数,以此类推。这里也可以调用方法来判断,但必须是类方法,并且返回值必须为BOOL类型。 样例:找出给[UIImage imageNamed:]传nil的代码。这里就需要设置Symbol为[UIImage imageNamed:],然后Condition设置为$arg3 == nil。这样在运行中如果遇到传nil就会触发断点。

查看某一个函数需要添加断点的符号填写格式(在需要调试的函数打上断点,程序运行走到断点后,从堆栈信息中查看相应函数的格式)

技巧五:全局异常断点(Add Exception Breakpoint)

技巧六:查看整体UI层级结构(debug view hierarchy)

如果电脑配置较低,最好使用chisel插件命令pviews

技巧七:开启僵尸模式(EXC_BAD_ACCESS)

遇到EXC_BAD_ACCESS这个错误,那就意味着你向一个已经释放的对象发送消息。Xcode知道这个对象是什么,所以可以让我们知道这个对象在哪里,以及这是什么时候发生的。当开启僵尸模式后,遇到EXC_BAD_ACCESS,xcode可以帮我们快速定位到出现问题的代码。

开启僵尸模式:

技巧八:查看frame的值

导入@import UIKit

(lldb) p self.view.frame
error: property 'frame' not found on object of type 'UIView *'
error: 1 errors parsing expression
(lldb) e @import UIKit
(lldb) p self.view.frame
(CGRect) $0 = (origin = (x = 0, y = 0), size = (width = 375, height = 667))

或者(CGRect)

print (CGRect)[view frame]
(CGRect) $1 = (origin = (x = 0, y = 0), size = (width = 200, height = 100))

技巧九:监听所有的点击事件(UIControl、Touch、Gesture)

方法:覆写UIAppliaction

.h文件

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface CustomApplication : UIApplication

@end

NS_ASSUME_NONNULL_END

.m文件

#import "CustomApplication.h"

@implementation CustomApplication
-(void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];
}
@end

main.m文件

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "CustomApplication.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc,
                                 argv,
                                 NSStringFromClass([CustomApplication class]),
                                 NSStringFromClass([AppDelegate class]));
    }
}
方法执行

一次事件可能会执行三次函数:-(void)sendEvent:(UIEvent *)event三次的force有区别


一次事件可能会执行两次函数:-(void)sendEvent:(UIEvent *)event两次的force没区别


响应者链条

1、如果是UIControl事件,集成UIResponder控件(UIButton)消息传递链(倒序)如下图所示


2、如果是UIGestureRecognizer手势事件,集成UIResponder控件(UIView)消息传递链(倒序)如下图所示


3、如果UIControlUIGestureRecognizer同时存在,优先级高

其他工具:1、Chisel

Chisel是faceBook开源的lldb调试命令集合

安装(具体参考

Chisel 使用 homebrew 来安装

brew update
brew install chisel

安装完成后,将下面的命令添加到~/.lldbinit中,xcode启动的时候才会加载chisel

command script import /usr/local/opt/chisel/libexec/fblldb.py

常用命令

查看帮助

(lldb) help

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

其他工具:2、Reveal

Reveal 绝对是iOS界面调试利器。使用起来不仅比Xcode自带流畅,而且功能更加多。由于收费,30天过后就没怎么用但是绝对好用。

大约有4中集成方法,详情参加官网

其他工具:3、FLEX

FLEX是Flipboard开源的一系列在应用中调试的工具集。FLEX以第三方库的形式集成在应用中,使用时将类库加到工程中,然后 通过调用[[FLEXManager sharedManager] showExplorer]; 就可显示出用于调试的工具栏进行调试。

它提供的功能如下:

  • 查看、修改views
  • 查看任何对象的属性
  • 动态的修改属性
  • 动态的调用实例方法和类方法
  • 查看网络请求过程
  • 添加模拟的键盘快捷键
  • 查看系统日志
  • 从堆中获取任何对象
  • 查看沙盒中的文件
  • 查看文件系统中的SQLite/Realm数据库
  • 在模拟器中触发3D touch
  • 查看你应用中所有的类
  • 快速获取常用的类,例如[UIApplication sharedApplication], the app delegate, the root view controller on the key window, and more.
  • 动态的查看NSUserDefaults里面的值

参考资料:

[译]用 LLDB 调试 Swift 代码

iOS高效调试