10

我有一系列“策略”对象,我认为这些对象可以方便地实现为一组策略类的类方法。我为此指定了一个协议,并创建了要遵守的类(如下所示)

@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 中?)

我的确切问题是,当我从数组中取出一个策略对象时,我想调用该方法:

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

我在返回语句上收到警告 - 它说 -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>. 在第二个中,您有一个符合<Counter>. 编译器警告是正确的,因为符合的实例<Counter>不响应countFor:,只有类才响应。

于 2009-06-01T09:10:01.660 回答
5

Objective-C 中的类确实像实例一样工作——主要的潜在区别是保留计数对它们没有任何作用。但是,您在 -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

事实证明它实际上正在工作并且警告不正确。

所以问题仍然在于它是否合理(如果它们不需要任何状态,则使用类方法)?

以及如何最好地处理警告(我喜欢免费运行警告)?

我唯一的解决方法是拥有第二个协议(与第一个协议基本相同,但在实例端声明它):

@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 回答