如何在XCode 4中特定类的特定属性的“objectAtIndex:”方法上设置断点?

时间:2012-12-10 17:40:31

标签: objective-c xcode xcode4 breakpoints

我想在" objectAtIndex上设置一个符号断点:"特定类别中特定属性的方法。

请参阅以下代码:

@interface Foo
...
@property (strong,nonatomic) NSMutableArray *fooArray;
...
@end

我尝试过以下事项:

  • -[[Foo fooArray] objectAtIndex:]
  • -[Foo::fooArray objectAtIndex:]
  • -[Foo::fooArray objectAtIndex]
  • Foo::fooArray::objectAtIndex:
  • Foo::fooArray::objectAtIndex
  • Foo::fooArray::objectAtIndex()

这些解决方案都不起作用。

有什么想法可以做到这一点吗?

3 个答案:

答案 0 :(得分:5)

不幸的是,虽然这很有用,但由于多种原因,它无法正常工作。

第一个涉及如何指定方法。用于标识断点中的方法的方法签名包含三个部分:

-¹[NSDictionary² objectForKey:³]
+¹[NSString² stringWithContentsOfURL:encoding:error:³]
  1. 这是实例方法( - )还是类方法(+)?
  2. 哪个班级实施此方法?
  3. 这种方法的选择器是什么?
  4. 所以你的第一个问题是你为#2写的不是一个类。

    你所拥有的是一个类,以某种方式跟随属性名称。这不起作用,因为调试器无法知道它是否是纯访问器 - 它无法确定您或实现该属性的任何人没有编写执行其他操作的自定义访问器。这意味着调试器没有良好,可靠的方法来获取该值,或者知道该值何时发生更改,而不会产生副作用。

    此外,类在方法签名中的作用是识别哪个类提供了您正在设置断点的实现。一旦你开始尝试引用一个包含对象的属性,那就会出现在窗口中,因为调试器需要一个类,并且必须从对象中获取它 - 并且看到之前的内容对于在任何时候都知道哪个对象的一些困难的段落。

    (公平地说,调试器确实可以观察实例变量-IIRC的值,两个调试器都可以在观察点中做到这一点,尽管观察点的可靠性在我最后一次尝试时是不稳定的。如果调试器可以将属性转换为其支持ivar,如果它有一个,并观察它,对于大多数属性来说它将是一个不错的90%解决方案,而这些解决方案没有富有想象力的存储实现和自定义访问器的支持。但是调试器今天不能这样做。)

    第二个原因是NSArray是一个类集群。

    您可能已经知道了第一部分(我怀疑这就是您尝试通过另一个属性指定单个对象的原因):

    NSArray和NSMutableArray都是抽象类,这反过来意味着没有人实现作为数组的业务;每一个都实现了一堆方便的方法,同时留下一组未实现的核心方法,供子类实现。

    因此,在创建NSArray时,不要创建NSArray。你得到的对象将是NSArray的一些私有子类的实例,它自己实现了它如何管理有序的对象列表的所有细节。

    所以你可以在-[NSArray objectAtIndex:]上设置断点,但它永远不会被击中,因为没有使用NSArray的objectAtIndex:实现 - 使用该实现是没有意义的,因为实现引发异常(旨在捕获忘记实现它的子类)。

    打破你问题的部分是:

    虽然NSArray的各种非必要方法的实现最终是根据核心方法定义的,例如objectAtIndex:,但这并不意味着子类必然会使用这些实现。如果objectAtIndex:不是最有效的方式来执行他们所做的事情,那么子类很可能有自己的实现不使用objectAtIndex:(例如,如果数组由链表支持而不是C数组)。

    所以,总结这个长篇答案:

    • 调试器无法可靠地监视属性的值。
    • 因此,当调用作为该属性值的对象类中的方法时,调试器不可能中断,因为设置断点的正确方法可能随时发生变化,并且调试器无法知道何时发生这种情况。
    • 即使您可以中断属性标识的某个对象的objectAtIndex:,该数组也可能永远不会使用objectAtIndex:,在这种情况下,您的断点永远不会被击中。

    你可能应该通过打破objectAtIndex:来提出另一个关于你想要做什么的问题。我假设您正在尝试调查您应用中的错误;那个bug可能是另一个有趣的问题。

答案 1 :(得分:5)

经过一番挖掘后,我找到了解决问题的方法。那有点难看。

它涉及在由第一个断点触发的命令中动态创建条件断点。

首先,每当你的fooArray准备好时休息。我选择了fooArray访问者,但可以提前完成:

breakpoint set --name "-[Foo fooArray]"

然后,当您在此特定数组对象上调用objectAtIndex:时,您想要的是中断。首先让我们把它的指针放在一个变量中:

expr id $watch = self->_fooArray

然后在条件中使用此变量创建一个新断点:

breakpoint set --name "-[__NSArrayI objectAtIndex:]" --condition "$rdi == $watch"

  • $rdi包含self,至少在x86_64。在ARM上使用$r0。 (见Clark Cox的great post on the topic。)
  • 永远不会调用
  • -[NSArray objectAtIndex:]。正如Peter所提到的,NSArray是一个类集群,你的数组实际上是__NSArrayI

或者,在Xcode中:

Xcode dynamic breakpoint

(别忘了查看“继续”框。)

它不是很漂亮,但似乎有效!

答案 2 :(得分:1)

我不在我的Mac上,所以我不能自己尝试,但是怎么样:

breakpoint set -n "-[[Foo fooArray] objectAtIndex:]"