我有一个我想调试的方法:
-(void)doAThingWithObject:(BaseDataObject *)dataObject //called VERY often
我在这个方法中有一个Xcode断点,我只想在BaseDataObject的某个子类上断点,所以我添加了一个带有条件的断点来检查该类:
[dataObject isKindOfClass:[SubClassOfBaseDataObject class]]
然而,这样做会导致解析错误!
Stopped due to an error evaluating condition of breakpoint 11.1: "[dataObject isKindOfClass:[SubClassOfBaseDataObject class]]"
Couldn't parse conditional expression:
error: no known method '+class'; cast the message send to the method's return type
error: 1 errors parsing expression
我已确保导入文件中的所有类,但调试器不知道我在条件中引用了哪个类。
但是,在断点之前的方法中创建所述Class的临时变量:
Class subClassCheck = [SubClassOfBaseDataObject class];
更新断点条件以引用临时变量:
[dataObject isKindOfClass:subClassCheck]
没有错误。
关于断点条件,我有点新手,有人可以解释为什么我的第一种方法不起作用吗?
答案 0 :(得分:8)
基于像Cocoa这样的大型框架的调试代码的一个复杂因素是编译器发出或调试器在您包含的框架的整个闭包中使用每种类型和函数是不实际的。因此编译器使用一些启发式方法来减少生成的调试信息量。它将仅为您实际使用的类型发出类型信息,并且定义方法的函数/ ObjC方法信息(与在头文件中声明的相反。)还有另一个小的微妙之处,即lldb将读取方法的类型信息。 ObjC运行时,尽管这些信息并不完整,因为它是针对运行时而不是调试器...所以我们有时似乎知道违反先前规则的ObjC方法。
另一个需要注意的重要事项是返回大于指针(如NSMakeRect等)的函数的调用约定是这样的,如果调试器调用一个函数,认为它返回一个指针,它实际上返回一个更大的结构,该行为将导致程序中的堆栈损坏。如果你很幸运,你会在你继续时立即崩溃,但如果你运气不好,它只会改变一些数据值并导致你花费数小时试图追逐一些实际上由调试器引起的有趣行为。因此调试器将拒绝调用无法确定其返回类型的函数。
无论如何,您得到的错误是因为调试器无法在对象上找到“+ class”方法的调试信息。这并不奇怪,因为“class”是NSObject上的一种方法而不是你的类。我不确定为什么我们在运行时找不到它,也许是因为它是一个类方法?这值得一个bug。我们显然从运行时获得了isKindOfClass的类型:或者你的解决方法也会失败。
在这种情况下,由于您实际上知道了类方法的返回类型,因此可以通过在断点表达式中明确地将其转换为调试器来解决缺乏知识的问题。在调试器的表达式解析器中转换函数返回有两个目的,一个是常规C语言函数,另一个是告诉调试器函数的返回类型,否则它无法弄清楚。一种仅适用于返回类型的短手原型。
类似于:
[dataObject isKindOfClass: (Class) [SubClassOfBaseDataObject class]]
应该无需更改代码即可运行。
另请注意,断点条件使用与“expr”或“print”命令相同的机制运行。因此,尝试断点命令的最简单方法是设置一个无条件断点,点击它,然后转到lldb控制台并使用“print”来玩,直到你得到一些有用的东西。