1

アプリでデータを表す方法は 2 つありUITableViewますUIScrollView
だから私は2つのメインクラスを持っています:AppTableView: UITableViewAppScrollView: UIScrollView. そして、両方のビューに同じ追加を実装したいと考えています。そこで、 と の 2 つのクラスSomeAdditionsTableView: UITableViewを作成しSomeAdditionsScrollView: UIScrollViewました。このクラスのコードは同じです。メインクラスは と のよう
AppTableView: SomeAdditionsTableViewになりAppScrollView: SomeAdditionsScrollViewました。

このコードの重複を避けるには? 前もって感謝します。

4

3 に答える 3

4

ええ、これは Objective-c の多重継承の欠如の問題です。ここで UIView と UIScrollView のサブクラスで特定のメソッドが個別に必要な場合、同じ問題がありました: Subclassing UIView vs UIScrollView。私が知っている3つの可能な解決策があります:

  1. いかなる種類のインスタンス変数も保存する必要がない場合は、UIScrollView でカテゴリを宣言し、そのカテゴリを 2 つのサブクラスにインポートしてください。これは最も簡単な解決策ですが、とにかくサブクラス化する場合はおそらく状態情報を保存する必要があるため、うまくいく可能性は最も低くなります。
  2. UITableViewのサブクラスのみを作成し、UITableViewが必要ない場合はUITableViewとして使用しないでください。技術的には、tableView のメソッドを呼び出さずに UITableView を UIScrollView として使用できます。もちろん、tableView (すべてのインスタンス変数) の「重み」を持ち歩くことになりますが、UITableView を UIScrollView だけでなく UITableView として使用する必要がある理由はありません。
  3. コードの重複を最小限に抑えるために、できるだけ多くのコードを別のオブジェクトに委譲します。個別のサブクラスごとに、メソッド デリゲートであるインスタンス変数を保持し、そのデリゲートへのメソッド呼び出しを転送します。ここからが楽しみです。プロトコルを使用して、サブクラスでデリゲート メソッドを宣言し、特別な NSObject メソッドをオーバーライドして、- (id) forwardingTargetForSelector:(SEL)aSelectorこれらのメソッド呼び出しがデリゲートに確実に送信されるようにすることができます。デリゲート クラスで宣言されたプロトコルに準拠するサブクラスでカテゴリを使用します。これにより、デリゲート クラスのすべてのメソッドがサブクラスに公開され、これらのメソッドをサブクラスに実際に実装する必要がなくなります。ランタイムがサブクラスで宣言されたメソッドを見つけることができない場合、それは呼び出します- (id) forwardingTargetForSelector:(SEL)aSelectorデリゲート/転送されたクラスを返すために使用できます。これにより、個々のメソッドを転送する必要がなくなります。これらのメソッド呼び出しが何をするかによって、これにはもう少し「配線」が必要になる場合がありますが、最終的に多くのコードを書く必要がなくなります。プロトコルを使用して、objective-c の多重継承を本質的に「模倣」します。詳細については、こちらの質問/回答を参照してください: https://stackoverflow.com/a/9419587/1147934

3 つのうち、最後のオプションが私にとって最も効果的です。理解するには少し手間がかかりますが、コードの重複を大幅に減らすことができます。サブクラス化せずにサブクラス化したい場合にも使用します。ただし、最大の要件は、これを行うクラスは、そのメソッド宣言をそのインターフェイスから別のプロトコルに移動する必要があるということです。しかし、それは実際には大したことではなく、「動作のような複数の継承」を得ることの利点は素晴らしいものです。

また、転送クラス (サブクラス) のインスタンス変数にアクセスするために転送クラスが必要になる場合があります。これを実現するには、デリゲート パターンを使用します。これにより、転送されるクラスは、これらのインスタンス変数にアクセスするために転送クラスへの弱い参照を維持します。たとえば、あなたの場合、UIScrollView で動作するメソッドを委任しようとしている場合、それらのメソッドはそのビューにアクセスできる必要がある場合があります。これらのメソッドがデリゲート クラスでスタックしている場合、ビューの変数に直接アクセスしない限り、それらのメソッドはビューの変数に直接アクセスできません。どのデリゲート パターンでもよくあることですが、保持サイクルを作成しないように十分注意してください。

于 2012-06-19T12:59:33.317 に答える
0

追加したものが独自の状態を必要としない場合は、それらを のカテゴリにすることができますUIScrollView。次に、 aUITableViewは の型であるUIScrollViewため、それらのいずれかでもカテゴリ メソッドを使用できます。

新しい変数を定義する必要がある場合は、それを独立したクラスにしてMyTableView : UITableView、プロパティを持つサブクラスを作成しSomeAdditions、同様にMyScrollView : UIScrollView.

于 2012-06-19T12:25:59.883 に答える
0

継承の「is_a」関係の代わりに、プロトコルと「has_a」関係を使用することで、多くのことを達成できます。
非常に一般的なパターンの 1 つはデリゲートですが、カプセル化またはラップされたオブジェクトへのメソッド呼び出しの転送にもプロトコルが役立ちます。
次の例では、互いに関連していないクラスが共通のオブジェクトを共有していますが、同じ種類のオブジェクトが異なるクラスのオブジェクトを使用し、すべてが共通のプロトコルを実装している可能性もあります。非常に異なるもの。

@interface ClassA : NSObject
@property (strong) id<BrainProtocol> *brain
@end

@@implementation ClassA
@synthezise brain;

-(void)theMethod
{
    [brain theMethod];
}
@end

@interface ClassB : NSObject
@property (strong) id<BrainProtocol> *brain
@end

@@implementation ClassB
@synthezise brain;

-(void)theMethod
{
    [brain theMethod];
}
@end

ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];

//A object, that implements the BrainProtocol

Brain *brain = [[brain alloc] init];
[a setBrain:brain];
[b setBrain:brain]; 
于 2012-06-19T14:01:19.223 に答える