Conditional Breakpoint (条件付きブレークポイント)
最近のIDEは例外なく高機能なデバッガを持っており、ブレークポイントにより実行中のコードを止める事が出来るのはもとより、ブレークポイントを実行する際に設定する任意の条件を言語と同じ文法で記述できる"Conditional Breakpoint"を使うことができる。
Xcodeもその例外ではなく非常にスマートなブレークポイント管理機能を持っており※、"Conditional Breakpoint"も設定できるのだが、その設定にはちょっと注意が必要である。
例えば以下は、とあるValueTransformer(NSObject->NSDictionary)の実装コードだが
- (id)transformedValue:(id)value { [self setSourceClass:[value class]]; NSArray* props = [BBProperty allProperties:[self sourceClass]]; NSMutableDictionary* dic = [[NSMutableDictionary alloc]initWithNullCapability:props.count]; // <= ここでプレーク for (BBProperty* p in props) { id newValue = [p propertyValueForTarget:value]; [dic setObject:newValue forKey:[p name]]; } return dic; }
このコンテキスト中で、以下の条件付きブレークポイントを設定した。
意味としてはプロパティの型をエンコードした文字が"T*"つまりchar*型だった場合にブレークすることを想定しており、条件はコード中のif文として記述した場合には問題無くコンパイルが通り実行できるのだが、これをそのまま実行すると条件は有効にならず、常時ブレークしてしまう。
デバッガを見ると設定したブレークポイントにエラーが発生しているようだ。
文字列定数@"T*"に対して送るメッセージ"-isEqual"を認識できないとある。更に式の戻り値がBOOLであることも認識できないようだ。条件をひっくり返してみたものの
結局色々試して上手く条件が設定できたのは以下のように記述した時だった。
-
- 左辺には文字列定数ではなくオブジェクトが戻る式に
- 式全体の戻り値の型をBOOLにキャスト
- 右辺にBOOL型の定数を使わずに整数を使用
どうやらXcodeのデバッガ(現在はLLDB)におけるブレークポイントの条件式はランタイムの型情報が一切使えず、定数を正しい型として認識することすらできないようだ。
※一括でブレークポイントをOn/Offできたり、モジュール毎に階層化されたブレークポイントや、グローバルに使える共有ブレークポイント、シンボリックブレークポイントなど、C系のIDEとしては非常にリッチな機能を持つ。