2010-12-12 15 views
11

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

私は スーパー EXC_BAD_ACCESSエラーがスローされますが、私は [self methodToCall][super methodToCall]からこれらの呼び出しを変更し、メッセージがレスポンダチェーンを上に移動させ、すぐとして、それがうまく働いたのメソッドを呼び出しました。

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

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

注:ブロックがプロパティに格納されてからブロック実装コードが呼び出されるまでには、コピーが使用されるため、ブロックのライフサイクルに問題はないと思われます大丈夫です。また、これはiPhoneデバイス(3G)でクラッシュするだけでしたが、iPhone Simulatorでクラッシュすることなく動作していました。 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]; 
} 
}]; 

答えて

11

技術的には、これは、Objective-Cランタイムの問題である、とsuperに呼び出す方法の根本的な仕組みは、実際に働いています。基本的には、メッセージの受信者であるオブジェクト(すべてのケースでself)とメソッドの特定のバージョン(メソッド実装が発生するクラスのスーパークラス)を実装するクラスの両方を取得します。このようなメッセージの送信の準備は、実行時ではなくコンパイル時に行われるため、ブロックと重複しても驚くことはありません。

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

しかし、私はあなたが常にこの作業に頼ることができるとは確信していません。ブロックは現在のランタイム状態を取得できますが、メソッドが実装されている階層レベルは、どの外部呼び出しに対しても不透明でなければならないため、カプセル化を中断してスーパークラスの実装を呼び出すことは実際には(OOPの観点からは)意味をなさないコード。私は継承階層に依存しない別の解決策を見出そうとします。EXC_BAD_ACCESSで

+0

詳細な説明をいただき、ありがとうございます。 – Andrew

+0

問題ありません。それは確かに以前に私に起こっていない興味深い問題です。 –

8

結果:コンパイラのバグがおそらく原因

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

。そのブロックの[self class];や他のメソッド呼び出しをselfに追加しようとすると、おそらく動作します。

-didRetrieveItemsおよび-errorRetrievingItemsの実装は完全にスーパークラスにあります。

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

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

私はあなたがオブジェクト指向プログラミングの基本的な側面の一つについて混同されるかもしれないと思います。あなたのクラスにはこれらのメソッドの実装はないと言います。それらはスーパークラスにしか存在しません。

継承のために、あなたのクラスは上記のメソッド呼び出しに効果的に応答します。 selfを使用して上記のように電話するだけです。それは見つけることができ、あなたはそれをやるべきである方法です!

+0

Doh、時々、私がやっていることを本当に考えずにタイプするだけです!何らかの理由で、レスポンダチェーンを上っていると思っていただけで、スーパークラスのメソッドを単に継承しているとは思えませんでした。見逃すような基本的な原則は、あなたにスポットです!それを私の注意を引くことに感謝します。 – Andrew

関連する問題