10

我想在特定类中特定属性的“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()

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

有什么想法可以解决问题吗?

4

3 回答 3

5

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

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

-¹[NSDictionary² objectForKey:³]
+¹[NSString² stringWithContentsOfURL:encoding:error:³]
  1. 这是实例方法(-)还是类方法(+)?
  2. 这个方法的哪个类的实现?
  3. 这个方法的选择器是什么?

所以你的第一个问题是你为#2写的不是一个类。

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

此外,类在方法签名中的作用是确定哪个类提供了您要设置断点的实现。当您开始尝试引用包含对象的属性时,它就会消失,因为调试器需要一个类,并且必须从对象中获取它 - 并参见上一段了解一些困难知道始终是哪个对象。

(公平地说,调试器确实有可能观察实例变量的值——IIRC,两个调试器都已经可以在观察点中执行此操作,尽管我上次尝试的观察点的可靠性是不稳定的。如果调试器可以将属性转换为其支持 ivar(如果有的话),并注意这一点,对于大多数属性来说,这将是一个不错的 90% 解决方案,这些属性不受富有想象力的存储实现和自定义访问器的支持。但调试器无法做到今天这个。)

第二个原因是 NSArray 是一个类簇。

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

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

所以,当你创建一个 NSArray 时,你并没有创建一个 NSArray。您返回的对象将是 NSArray 的某个私有子类的一个实例,它自己实现了它如何管理对象的有序列表的所有细节。

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

打破你的问题的部分是:

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

所以,总结一下这个长答案:

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

你可能应该问另一个问题,关于你试图做的任何事情objectAtIndex:。我假设您正在尝试调查应用程序中的错误;该错误可能是另一个有趣的问题。

于 2012-12-11T18:22:53.440 回答
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$r0在 ARM 上使用。(请参阅克拉克考克斯关于该主题的精彩帖子。)
  • -[NSArray objectAtIndex:]永远不会被调用。正如彼得所提到的, NSArray 是一个类集群,而您的数组实际上是一个__NSArrayI.

或者,在 Xcode 中:

Xcode 动态断点

(不要忘记选中“继续”框。)

这不是很漂亮,但它似乎工作!

于 2012-12-11T20:51:00.567 回答
1

我不在我的 Mac 上,所以我不能自己尝试,但是如何:

breakpoint set -n "-[[Foo fooArray] objectAtIndex:]" 
于 2012-12-11T12:44:22.733 回答