web-dev-qa-db-ja.com

Objective-Cのカテゴリを使用したメソッドのオーバーライド

クラスカテゴリを使用して、カテゴリを使用して既に実装されているメソッドをオーバーライドできますか?このような:

1)独自の方法

-(BOOL) method {
  return true;
}

2)オーバーライドされたメソッド

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

これは機能しますか、それとも違法ですか?

86
retix

Appleドキュメント から:

現在、Objective-C言語では、カテゴリを使用してクラスが継承するメソッド、またはクラスインターフェイスで宣言されているメソッドをオーバーライドすることもできますが、そうすることは強くお勧めしません。カテゴリは、サブクラスの代替ではありません。カテゴリを使用してメソッドをオーバーライドすることには、いくつかの重大な欠点があります。

  • カテゴリが継承されたメソッドをオーバーライドする場合、カテゴリ内のメソッドは通常どおり、superへのメッセージを介して継承された実装を呼び出すことができます。ただし、カテゴリがクラスのクラスに存在するメソッドをオーバーライドする場合、元の実装を呼び出す方法はありません

  • カテゴリは、同じクラスの別のカテゴリで宣言されたメソッドを確実にオーバーライドすることはできません。

    Cocoaクラスの多くはカテゴリを使用して実装されているため、この問題は特に重要です。オーバーライドしようとするフレームワーク定義のメソッド自体がカテゴリに実装されている可能性があるため、どの実装が優先されるかは定義されていません。

  • 一部のカテゴリメソッドが存在すると、すべてのフレームワークで動作が変更される場合があります。たとえば、NSObjectのカテゴリでwindowWillClose:デリゲートメソッドをオーバーライドすると、プログラム内のすべてのウィンドウデリゲートはカテゴリメソッドを使用して応答します。 NSWindowのすべてのインスタンスの動作が変わる場合があります。フレームワーククラスに追加したカテゴリは、動作に神秘的な変化を引き起こし、クラッシュを引き起こす可能性があります。

142
Benoît

これを行うには、 クラスクラスター アプローチを採用するか、 methods swizzling テクニックを使用します。

それ以外の場合、2つ以上のcategorizedメソッドの動作は ndefined

18
Martin Babacaev

古いドキュメントリンクは無効です。私が見つけた最高の代替品はここにありました: Apple Docs

カテゴリメソッド名の衝突を避ける

カテゴリで宣言されたメソッドは既存のクラスに追加されるため、メソッド名に注意する必要があります。

カテゴリで宣言されたメソッドの名前が元のクラスのメソッド、または同じクラス(またはスーパークラス)の別のカテゴリのメソッドと同じ場合、動作はどのメソッド実装が使用されるかに関して未定義ですランタイム。独自のクラスでカテゴリを使用している場合、これは問題になる可能性は低くなりますが、カテゴリを使用して標準のCocoaまたはCocoa Touchクラスにメソッドを追加すると問題が発生する可能性があります。

Appleより軽いタッチを使用しますが、主なポイントは同じです。予測できない動作は沈黙しているため、災害を招きます。

8
AmitaiB

カテゴリを使用して、基本クラスの既存のメソッド(たとえば、車クラスの駆動メソッド)をオーバーライドすることもできますが、これは絶対にしないでください。問題は、カテゴリがフラットな組織構造であるということです。 Car + Maintenance.mの既存のメソッドをオーバーライドし、その動作を別のカテゴリで再度変更することを決定した場合、Objective-Cが使用する実装を知る方法はありません。このような状況では、ほとんどの場合、サブクラス化の方が優れたオプションです。

このチュートリアルから http://rypress.com/tutorials/objective-c/categories

2
Vinuta