注意:解释起来相当复杂。请跟我一起讨论这个。
大家好,
我正在实现一个应用程序,其中类的实例和类本身都有“子”(放在NSMutableArray
内)。这是一个非常复杂的应用程序,但是由于Objective-C,它很轻松:类本身就是对象,可以有方法和“变量”(借助静态变量等)。
为了让自己变得简单,我在我的实例(使用-
)和类(使用+
)上实现了accessor / setter方法来获取和操作“children”而无需直接访问数组。我喜欢让我的对象尽可能地关闭,并且方法会进行一些数据验证。
我还从NSFastEnumeration
协议实现了快速枚举实例方法。这里有一个问题:我可以实现快速枚举类方法并将其与Objective-C的for...in
构造一起使用吗?顺便说一下,我可以实现这个:
+ (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (__unsafe_unretained id [])buffer count: (NSUInteger)len;
然后在这样的地方使用它:
for (id child in [MyClass class]) {
// Do magic stuff…
}
我偷看了GNUStep的GSFastEnumeration.h
文件,该文件将快速枚举实现为宏,这证实了上述情况是可行的,但我不确定Apple是否也这样做。
即使我无法将NSFastEnumeration
协议与我的类对象相关联,也可以在没有该协议的情况下进行快速枚举(并且面向未来)?
感谢。
答案 0 :(得分:3)
方法-countByEnumeratingWithState:objects:count:
是快速枚举的全部 - 我相信协议主要用于描述(实现协议比使用正确的签名声明方法更容易)。我希望它能正常工作,但我没有参考。不过,您可能希望循环遍历[MyClass class]
。
我可能认为它具有前瞻性。请注意,在类对象周围创建一个小的包装类,除了实现NSFastEnumeration
之外什么都不做,并将实例方法-countByEnumeratingWithState:objects:count:
转发给类的方法+countByEnumeratingWithState:objects:count:
,这真是微不足道。
答案 1 :(得分:1)
我建议使用与NSFastEnumeration
方法相同的类方法创建协议。然后,您可以将[MyClass class]
作为John Calsbeek mentioned进行迭代。
//Protocol implementation
@protocol FastClassEnumeration <NSObject>
@required
+ (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len;
@end
//Class implementation
@interface EnumeratedClass : NSObject<FastClassEnumeration>
@end
@implementation EnumeratedClass
+ (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len
{
static const unsigned long items_length = 4;
static NSString * items[items_length] = { @"item1", @"item2", @"item3", @"item4" };
if(state->state >= items_length)
{
return 0;
}
state->itemsPtr = items;
state->state = items_length;
state->mutationsPtr = (unsigned long *)self;
return items_length;
}
@end
//Usage
...
for(NSString *item in [EnumeratedClass class])
{
NSLog(@"%@", item);
}
...
答案 2 :(得分:1)
我可以......?
嗯,你试过吗?它有用吗?如果你已经尝试过,你会发现它确实可以编译并运行。
为什么不应该呢?类对象就像其他对象一样是对象。类方法只是碰巧在类对象上的方法。如果向类对象发送消息,它将调用类方法;而如果您向非类对象发送消息,它将调用实例方法。所以,您可以将类方法放在类上,并使用类对象,就像使用普通对象一样,将实例方法放在其类上。
唯一可能的区别是类对象不会明确地符合NSFastEnumeration
协议,类似于循环于其类没有明确指定它符合{{1}的普通对象的情况。 } 协议。所以问题是,在使用它之前,它们是否检查对象是否明确符合协议(而不是检查它是否响应选择器)?
根据我的经验,对于几乎所有的Cocoa,对于那些声称需要符合协议的对象的API,您可以提供一个不明确符合协议但实现所有协议方法的对象,它会工作正常。 (他们如何检查它?如果他们使用NSFastEnumeration
,那对于类对象不起作用,因为有一个conformsToProtocol:
,它有不同的含义。他们必须使用运行时函数或特殊 - 案例类对象可能。)例如,+conformsToProtocol:
文档说它的键必须符合NSDictionary
,但如果你有一个不符合NSCopying
的对象,但是实现了NSCopying
,它运作正常。 (事实上,有一个copyWithZone:
方法,其声明的目的是允许将类对象用作字典键,因此很明显,键不需要明确地符合+copyWithZone:
。 )