10

ポリシー クラスのセットでクラス メソッドとして実装すると便利だと思われる一連の「ポリシー」オブジェクトがあります。このためのプロトコルを指定し、準拠するクラスを作成しました (以下に示すのは 1 つだけです)。

@protocol Counter   
+(NSInteger) countFor: (Model *)model;
@end

@interface CurrentListCounter : NSObject <Counter> 
+(NSInteger) countFor: (Model *)model;
@end

次に、このプロトコルに準拠するクラスの配列があります (CurrentListCounter のように)

+(NSArray *) availableCounters {
return [[[NSArray alloc] initWithObjects: [CurrentListCounter class], [AllListsCounter class], nil] autorelease];
}

オブジェクトのようなクラスをどのように使用しているかに注意してください (これは私の問題かもしれません。Smalltalk では、クラスは他のすべてのオブジェクトと同じようにオブジェクトです。Objective-C にあるかどうかはわかりません)。

私の正確な問題は、配列からポリシー オブジェクトの 1 つを取得するときにメソッドを呼び出したい場合です。

id<Counter> counter = [[MyModel availableCounters] objectAtIndex: self.index];
return [counter countFor: self];

return ステートメントで警告が表示されます - -countFor: not found in protocol と表示されます (そのため、クラス メソッドを呼び出したいインスタンス メソッドを想定しています)。ただし、配列内のオブジェクトはクラスのインスタンスであるため、インスタンス メソッドのようになりました (概念的にはそうあるべきです)。

クラスメソッドを呼び出す魔法の方法はありますか? それとも、これは単に悪い考えであり、ポリシー オブジェクトのインスタンスを作成するだけでよいのでしょうか (クラス メソッドは使用しないでください)。

4

3 に答える 3

20

これ

id <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );

する必要があります

Class <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );

最初に、に準拠するインスタンスがあります<Counter>。2番目には、に準拠するクラスがあります<Counter><Counter>に準拠するインスタンスは に応答せずcountFor:、クラスのみが応答するため、コンパイラの警告は正しいです。

于 2009-06-01T09:10:01.660 に答える
5

Objective-C のクラスはインスタンスのように機能します。主な根本的な違いは、retain カウントがそれらに対して何もしないことです。ただし、 -availableCounters 配列に格納しているのはインスタンス (id型) ではなく、型を持つクラスですClass。したがって、上で指定した -availableCounters 定義では、必要なものは次のとおりです。

Class counterClass = [[MyModel availableCounters] objectAtIndex: self.index];
return ( [counterClass countFor: self] );

ただし、クラスではなくインスタンスを使用した方がおそらく意味的に優れているでしょう。その場合、次のようなことができます。

@protocol Counter
- (NSUInteger) countFor: (Model *) model;
@end

@interface CurrentListCounter : NSObject<Counter>
@end

@interface SomeOtherCounter : NSObject<Counter>
@end

次に、モデル クラスは次のように実装できます。

static NSArray * globalCounterList = nil;

+ (void) initialize
{
    if ( self != [Model class] )
        return;

    globalCounterList = [[NSArray alloc] initWithObjects: [[[CurrentListCounter alloc] init] autorelease], [[[SomeOtherCounter alloc] init] autorelease], nil];
}

+ (NSArray *) availableCounters
{
    return ( globalCounterList );
}

次に、それを使用すると、上記で指定したとおりになります。

id<Counter> counter = [[Model availableCounters] objectAtIndex: self.index];
return ( [counter countFor: self] );
于 2009-05-31T12:28:27.193 に答える
0

実際に機能しており、警告が正しくないことがわかりました。

それで、それが合理的なことであるかどうかという疑問はまだ残っています(状態が必要ない場合はクラスメソッドを使用します)?

そして、警告を最も適切に処理するにはどうすればよいですか (警告なしで実行したい)?

私の唯一の回避策は、2 番目のプロトコルを用意することでした (基本的には最初のプロトコルと同じですが、インスタンス側で宣言します)。

@protocol CounterInstance
-(NSInteger) countFor: (Model *)model;
@end

そして、カウンターにアクセスする場所では、代わりにそれを使用します(コンパイラーをだますため):

id<CounterInstance> counter = [[MyModel availableCounters] objectAtIndex: self.index];
return [counter countFor: self];

少し厄介ですが、機能します。他の人からの意見に興味がありますか?

于 2009-05-31T12:25:36.920 に答える