11

Objective-C ブロックの実装では、 superでのメソッドの呼び出しはサポートされていますか?

superでメソッドを呼び出していたときにEXC_BAD_ACCESSエラーがスローされましたが、これらの呼び出しを to から[super methodToCall]toに変更[self methodToCall]し、メッセージをレスポンダー チェーンの上に移動させるとすぐに、問題なく動作しました。

ブロックが存在するクラスのインスタンスには の実装はありませんが-methodToCall、スーパークラス (つまり、自己の継承元のクラス) には実装があります。

ブロックの実装内でスーパーでメソッドを呼び出すことがそもそも(技術的に)問題だった理由の詳細を知りたいので、将来それを避けることができます。変数がブロックでどのようにキャプチャされるか、およびスタックとヒープに関する何かに関連しているのではないかと疑っていますが、具体的な考えはありません。

注: ブロックの実装コードは、ブロックがプロパティに格納されてから数秒後に呼び出されます。プロパティはコピーを使用するため、ブロックのライフサイクルの問題ではないと思います。すべて問題ないようです。また、これは iPhone デバイス (3G) でのみクラッシュしていましたが、iPhone シミュレーターではクラッシュすることなく機能していました。

結果EXC_BAD_ACCESS:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

完璧に動作し、スーパークラスに実装-didRetrieveItemsされています。-errorRetrievingItems

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];
4

2 に答える 2

11

技術的には、これは Objective-C ランタイムの問題であり、呼び出しがsuper実際にどのように機能するかという基本的な仕組みの問題です。self基本的に、メッセージの受信者であるオブジェクト (すべての場合) と、メソッドの特定のバージョンを実装するクラス (メソッドの実装が発生するクラスのスーパークラス) の両方をキャプチャします。このようなメッセージ送信の準備の多くは、実行時ではなくコンパイル時に行われるため、ブロックとの相互作用が悪くても驚かないでしょう。

selfメッセージが送信されようとしているときにまだ有効かどうかを確認します。通常、ブロック内で参照されているオブジェクトはすべて自動的に保持されます。動作が少し異なるため、期待どおりに保持さsuperれていない可能性があります。selfこれを確認する簡単な方法の 1 つはsuper、最初に記述された への呼び出しを使用し、 と呼ばれるオブジェクトを単純にリークしてself、それが機能するかどうかを確認することです。これが問題であることが判明した場合はself、ブロック内にダミー参照を挿入して、自動メモリ管理を取得する必要がある場合があります。

ただし、厳密な意味では、これがいつまでも機能することに依存できるかどうかはわかりません。ブロックは現在のランタイム状態をキャプチャできますが、メソッドが実装されている階層レベルは外部呼び出しコードに対して不透明であるため、ブロックがカプセル化を破ってスーパークラスの実装を呼び出すことは (OOP の観点から) 意味がありません。継承階層に依存しない別の解決策を見つけようとします。

于 2010-12-12T03:12:00.230 に答える
8

EXC_BAD_ACCESS の結果:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

おそらくコンパイラのバグが原因です。そのブロックで自分自身に追加する[self class];か、他のメソッド呼び出しを試してみてください。おそらくうまくいくでしょう。

完璧に動作し、-didRetrieveItems と -errorRetrbeingItems の実装はスーパークラスにあります。

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

オブジェクト指向プログラミングの基本的な側面の 1 つについて混乱していると思います。クラスにはこれらのメソッドの実装はなく、スーパークラスにのみ存在するとおっしゃっています。

継承により、クラスは上記のメソッド呼び出しにも効果的に応答します。を使用して上記と同じように呼び出すだけですself。それは機能し、まさにあなたがそれを行うべき方法です!

于 2010-12-12T03:30:24.633 に答える