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

残念ながら、これは便利ですが、さまざまな理由で機能しません。

1つ目は、メソッドの指定方法です。ブレークポイントでメソッドを識別するためのメソッドシグネチャには、次の3つの部分があります。

-¹[NSDictionary² objectForKey:³]
+¹[NSString² stringWithContentsOfURL:encoding:error:³]
  1. これはインスタンスメソッド(-)ですか、それともクラスメソッド(+)ですか?
  2. このメソッドのどのクラスの実装ですか?
  3. このメソッドのセレクターは何ですか?

したがって、最初の問題は、#2のために書いたものがクラスではないということです。

あなたが持っているのはクラスであり、その後に何らかの形でプロパティ名が続きます。デバッガーにはそれが純粋なアクセサーであるかどうかを知る方法がないため、これは機能しません。ユーザーまたはそのプロパティを実装した人が、他のことを行うカスタムアクセサーを作成しなかったことを確認できません。これは、デバッガーには、潜在的に副作用を発生させることなく、その値を取得したり、その値がいつ変更されたかを知るための優れた信頼できる方法がないことを意味します。

さらに、メソッドシグネチャでのクラスの役割は、ブレークポイントを設定している実装を提供するクラスを識別することです。デバッガーにはクラスが必要であり、オブジェクトから取得する必要があるため、代わりにオブジェクトを保持するプロパティを参照しようとするとすぐにウィンドウが消えます。前の段落で、常にどのオブジェクトであるかを知る。

(公平を期すために、デバッガーがインスタンス変数の値を監視することは確かに可能です。IIRC、ウォッチポイントの信頼性は前回試したときに不安定でしたが、両方のデバッガーはすでにウォッチポイントでこれを実行できます。デバッガーの場合プロパティをバッキングivarに変換し、それを監視すると、想像上のストレージ実装やカスタムアクセサーによってバッキングされていない、ほとんどのプロパティに対して適切な90%のソリューションになりますが、デバッガーはそれを実行できません。これは今日です。)

2番目の理由は、NSArrayがクラスクラスターであるということです。

あなたはおそらくこれの最初の部分をすでに知っているでしょう(私はあなたが別のプロパティによって単一のオブジェクトを指定しようとしている理由だと思います):

NSArrayとNSMutableArrayはどちらも抽象クラスです。つまり、どちらも配列であるというビジネスを実装していません。サブクラスが実装できるように、コアメソッドの選択されたセットを実装せずに、それぞれが多数の便利なメソッドを実装します。

したがって、NSArrayを作成するときは、NSArrayを作成しません。返されるオブジェクトは、NSArrayのプライベートサブクラスのインスタンスであり、オブジェクトの順序付きリストを管理する方法のすべての詳細が独自に実装されています。

たとえば、ブレークポイントを設定することはできますが、-[NSArray objectAtIndex:]NSArrayの実装を使用するものがないため、ヒットすることはありませobjectAtIndex:ん。その実装は例外を発生させるため、その実装を使用する意味はありません(実装を忘れたサブクラスをキャッチすることを目的としています)。それ)。

あなたの質問を壊す部分は次のとおりです:

NSArrayのさまざまな必須ではないメソッドの実装は、最終的にはなどのコアメソッドの観点から定義されますがobjectAtIndex:、サブクラスがそれらの実装を使用するようにバインドされているわけではありません。サブクラスは、それを実行するための最も効率的な方法ではない場合(たとえば、配列がC配列ではなくリンクリストによってサポートされている場合)、をobjectAtIndex:使用しない独自の実装を持つことができます。objectAtIndex:

したがって、この長い答えを要約すると、次のようになります。

  • デバッガーがプロパティの値を確実に監視することはできません。
  • そのため、そのプロパティの値であるオブジェクトのクラスのメソッドが呼び出されたときにデバッガーがブレークすることはできません。これは、ブレークポイントを設定する正しいメソッドがいつでも変更される可能性があり、デバッガーができないためです。それがいつ起こるかを知っています。
  • 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"

  • $rdiself少なくとも にが含まれていx86_64ます。$r0ARM で使用します。(このトピックに関する Clark Cox のすばらしい投稿を参照してください。)
  • -[NSArray objectAtIndex:]呼び出されることはありません。Peter が述べたように、NSArray はクラス クラスターであり、配列は実際には__NSArrayI.

または、Xcode で:

Xcode 動的ブレークポイント

(「続行」ボックスをチェックすることを忘れないでください。)

それは本当に美しくはありませんが、うまくいくようです!

于 2012-12-11T20:51:00.567 に答える
1

私は自分の Mac を使用していないので、これを自分で試すことはできませんが、次の方法はどうでしょうか。

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