对类对象的快速枚举

时间:2012-08-24 14:05:09

标签: objective-c oop class foundation fast-enumeration

注意:解释起来相当复杂。请跟我一起讨论这个。

大家好,

我正在实现一个应用程序,其中类的实例和类本身都有“子”(放在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协议与我的类对象相关联,也可以在没有该协议的情况下进行快速枚举(并且面向未来)?

感谢。

3 个答案:

答案 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:。 )