如何在 Objective C 中调用类方法而不引用类?

发布于 2024-07-22 20:44:37 字数 966 浏览 4 评论 0原文

我有一系列“策略”对象,我认为将它们作为一组策略类上的类方法来实现很方便。 我为此指定了一个协议,并创建了符合该协议的类(下面仅显示一个),

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

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

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

我在 return 语句上收到警告 - 它说 -countFor:在协议中找不到(因此假设它是一个我想调用类方法的实例方法)。 然而,由于我的数组中的对象是类的实例,它们现在就像实例方法(或者从概念上讲它们应该是)。

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

I have a series of "policy" objects which I thought would be convenient to implement as class methods on a set of policy classes. I have specified a protocol for this, and created classes to conform to (just one shown below)

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

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

I then have an array of the classes that conform to this protocol (like CurrentListCounter does)

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

Notice how I am using the classes like objects (and this might be my problem - in Smalltalk classes are objects like everything else - I'm not sure if they are in Objective-C?)

My exact problem is when I want to call the method when I take one of the policy objects out of the array:

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

I get a warning on the return statement - it says -countFor: not found in protocol (so its assuming its an instance method where I want to call a class method). However as the objects in my array are instances of class, they are now like instance methods (or conceptually they should be).

Is there a magic way to call class methods? Or is this just a bad idea and I should just create instances of my policy objects (and not use class methods)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ㄟ。诗瑗 2024-07-29 20:44:37

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] );

A class in Objective-C does work like an instance -- the main underlying difference is that retain counting does nothing on them. However, what you're storing in the -availableCounters array aren't instances (the id type) but classes, which have a type of Class. Therefore, with the -availableCounters definition you specified above, what you need is this:

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

However, it would probably be semantically better if you used instances rather than classes. In that case, you could do something like the following:

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

@interface CurrentListCounter : NSObject<Counter>
@end

@interface SomeOtherCounter : NSObject<Counter>
@end

Then your model class could implement the following:

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 );
}

Then your use of that would be exactly as you specified above:

id<Counter> counter = [[Model availableCounters] objectAtIndex: self.index];
return ( [counter countFor: self] );
╰◇生如夏花灿烂 2024-07-29 20:44:37

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

应该是

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

首先您有一个符合 的实例。 在第二个中,您有一个符合 的类。 编译器警告是正确的,因为符合 的实例不会响应 countFor:,只有类会响应。

This

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

Should be

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

In the first you have an instance that conforms to <Counter>. In the second you have a class that conforms to <Counter>. The compiler warning is correct because instances that conform to <Counter> don't respond to countFor:, only classes do.

潦草背影 2024-07-29 20:44:37

事实证明它确实有效并且警告是不正确的。

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

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

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

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

并且在我访问计数器的地方使用它(以欺骗编译器):

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

它有点尴尬,但确实有效。 对其他人的观点感兴趣吗?

It turns out it is actually working and the warning is incorrect.

So the question still stands as to whether its a reasonable thing to do (use class methods if they don't need any state)?

And how to best handle the warning (I like to run warning free)?

My only workaround was to have a second protocol (essentially the same as the first but declare it on the instance side):

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

And where I access the counters use it instead (to trick the compiler):

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

Its a bit awkward but does work. Am interested in views from others?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文