2009-06-15 8 views
3

メソッドAを呼び出す際にAImpl()メソッドを呼び出すと同時に、メソッドAを別の時間に呼び出してBImpl()を呼び出すため、メソッドディスパッチテーブルを設定すると便利なことがあります。 Objective-Cでは、システムによって自動的に呼び出されるメソッド(delegateメソッドなど)に対して、これをどのように行うことができますか?Objective-Cでメソッドディスパッチテーブルを実装または変更する方法は?

たとえば、システムが初めてviewDidAppearを呼び出すと、viewAppearFirstTimeを呼び出す必要があります。その後、viewDidAppearを呼び出すと、(ブーリアンフラグを使用してコード内でif-elseチェックを行う代わりに)まったく異なるメソッド本体がヒットします。

別の例では、UIViewのdrawRectがアプリで非常に頻繁に呼び出されていますが、最初に呼び出されたdrawRectが後のものと異なる場合は、if-testを含めることは望ましくありません。最初に読んだ後にチェックも不要です。

+0

これはシングルトンでないクラスでは非常に問題です。メソッドルックアップテーブルはインスタンスではなくクラスであるため、スウィズルがクラスのすべてのインスタンスに適用されるためです。 – Chuck

+0

クラスのチャックリマッピング実装に同意すると、追跡が非常に難しい多くのバグが発生する可能性があります。また、私はコードを「読みにくくする」というあなたの主張に同意しません。標準パターンのいずれかを使用すると、ジュニアプログラマでもコードを読むのはかなり簡単です。あなたの解決策は、コードをより困難にする、すなわち「読みにくくする」ようにします。 –

+0

最初のdrawRect:が以降のdrawRect:呼び出しと異なる必要がある場合について説明できますか?キャッシュする場合は、drawRectではなくgetterにキャッシュします。ビューは画面上で出て来ることができるので、drawRect:への「最初の」呼び出しが何を意味するかははっきりしていません。最初の授業は?例えば初めて?私たちがスクリーンに置かれて以来初めて?最初にビューがロードされてから(何度も起こることがあります)?あなたが攻撃している具体例がありますか? –

答えて

3

私はここで注意してください:このような場合は、あなたが記述している特別なケースはあまりありません。ほとんど確実に使いすぎで、viewWillAppearという2つのバージョンではなく、viewDidLoadviewWillAppearに分かれているはずです。それは問題が浮上していると言いました。

これは私がしたいことを指し示すSELのままにしておくことをお勧めします。例えば、私は複雑な非同期の活動の後に「次のアクション」のためのこの種の技術を使用します。

if (self.nextActionSelector != NULL) 
{ 
    [self performSelector:self.nextActionSelector]; 
} 

だから、これのために、あなたは時間をかけて変更されるだろう、とviewWillAppearはちょうど何でも呼ぶようviewWillAppearSelectorを使用することができますそれはを指します。

ベンが推奨する方法スウィズルは、場合によっては便利ですが、自分ではなく既存のオブジェクトの動作を変更しようとしているときによく使用されます。それは本当にデバッグの楽しみを作ることができます.... OK、実際には楽しいものではありません。痛いとても痛い。

それ以外では、私は-forwardInvocation:を見ると、直接実装していないメッセージに応答することができます。呼び出しを書き換えて、本当に必要なメソッドを呼び出すことができます。しかし、これは実際に使用される方法ではありません。他のオブジェクトへの呼び出しを透過的に転送するためのものです。しかし、少なくともデバッグすることは、デバッガが期待するところに行くので難しくありません。

通常、この場合、ブール値ではなく、前に実行した証拠を探します。 viewが既に設定されているかどうかを確認したり、初めて特殊な変数を必要としないように初期化された他の値をチェックして、状態がクリアなものに弾力をつけます(メモリが逼迫しているiPhoneのダンプのような) 。可能な限り、私はこれらのものを外部のパーティに特別な初回ロジックを持たせるのではなく、ゲッタで自己初期化させる。ロジックをここに単純にしておくと、メンテナンスがずっと楽になりますね。NSInvocationは狂っています(テストではメソッド呼び出しより約500倍遅いですが、私はパフォーマンス、メンテナンス性についてこの決定を下すことを示唆していません)。

2

thisを入力し、NSInvocationのインスタンスをNSDictionaryに入れます。

2

Objective-Cランタイムでは、実行時にセレクタからメソッド実装へのマッピングを変更することができ、かなり滑らかです。詳細については、CocoaDevのこの記事をご覧ください:CocoaDev: Method Swizzling obj-cランタイムで必要な機能を効果的に置き換えるために、既存のマッピングを持つすべての関数をswizzleすることができます。

あなたはどこからでもすべきではありません。まずNSInvocationsを試してみましょう。独自のviewDidAppear関数を記述し、viewAppearFirstTime:関数を呼び出すことができるので、その中からメソッドswizzlingがおそらく過剰です。

幸運を祈る!

2

すべてのインスタンスのメソッドを変更したい場合は、メソッドswizzlingで行うことができます。私はこの目的のために使用されていることは聞いたことがありませんが、の中からclass_replaceMethodを使用してあなたが望むものを達成することができるかもしれません。あなたは、単一のインスタンスのメソッドディスパッチを変更したい場合は

しかし、私はあなたの唯一のオプションは、最初とそれに続く出演で別の方法を必要としない再設計を検討するためにあなたのviewDidAppear方法または内の条件文だと思います(あなたの説明から、あなたのコードをviewDidLoadviewWillAppearに分けるのは意味があるようです)。

関連する問題