如何在不引用类的情况下调用Objective C中的+ class方法?

Tim*_*imM 10 metaprogramming objective-c class-method

我有一系列"策略"对象,我认为这些对象可以作为一组策略类的类方法实现.我为此指定了一个协议,并创建了符合的类(如下所示)

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

@interface CurrentListCounter : NSObject <Counter> 
+(NSInteger) countFor: (Model *)model;
@end
Run Code Online (Sandbox Code Playgroud)

然后我有一个符合这个协议的类的数组(像CurrentListCounter那样)

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

注意我是如何使用像对象这样的类(这可能是我的问题 - 在Smalltalk类中,对象就像其他所有 - 我不确定它们是否在Objective-C中?)

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

id<Counter> counter = [[MyModel availableCounters] objectAtIndex: self.index];
return [counter countFor: self];
Run Code Online (Sandbox Code Playgroud)

我在return语句中得到一个警告 - 它表示-countFor:在协议中找不到(所以它假定它是一个实例方法,我想调用一个类方法).但是,由于我的数组中的对象是类的实例,它们现在就像实例方法(或者概念上它们应该是).

有没有一种神奇的方法来调用类方法?或者这只是一个坏主意,我应该只创建我的策略对象的实例(而不是使用类方法)?

Jon*_*ess 20

这个

id <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );
Run Code Online (Sandbox Code Playgroud)

应该

Class <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );
Run Code Online (Sandbox Code Playgroud)

在第一个你有一个符合的实例<Counter>.在第二个你有一个符合的类<Counter>.编译器警告是正确的,因为符合的实例<Counter>不响应countFor:,只有类执行.


Jim*_*vey 5

Objective-C中的类确实像实例一样工作 - 主要的不同之处在于保留计数对它们没有任何作用.但是,您在-availableCounters数组中存储的不是实例(id类型),而是具有类型的类Class.因此,使用上面指定的-availableCounters定义,您需要的是:

Class counterClass = [[MyModel availableCounters] objectAtIndex: self.index];
return ( [counterClass countFor: self] );
Run Code Online (Sandbox Code Playgroud)

但是,如果您使用实例而不是类,则可能在语义上更好.在这种情况下,您可以执行以下操作:

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

@interface CurrentListCounter : NSObject<Counter>
@end

@interface SomeOtherCounter : NSObject<Counter>
@end
Run Code Online (Sandbox Code Playgroud)

然后您的模型类可以实现以下内容:

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 );
}
Run Code Online (Sandbox Code Playgroud)

然后你使用它就像你上面指定的那样:

id<Counter> counter = [[Model availableCounters] objectAtIndex: self.index];
return ( [counter countFor: self] );
Run Code Online (Sandbox Code Playgroud)