在Objective-C中如何处理相关对象的NSArray

时间:2013-08-27 12:07:03

标签: objective-c cocoa nsarray subclassing

Animal是一个名为BOOL的{​​{1}}属性的类。 aliveMonkeyZebraWalrus的子类。如果我有一个名为Animal的{​​{1}}实例,其中包含NSArrayzooMonkey的混合实例,我想找到第一个活着的Zebra实例,我可能会这样做:

Walrus

问题是当我设置Zebra时,编译器会抱怨指针类型不兼容。如果我像Zebra *zebra; for (Animal *animal in zoo) { if ([animal isMemberOfClass:[Zebra class]] && animal.alive) { zebra = animal; break; } } 那样进行一些投射,那么它似乎有效,但我不确定在Objective-C中这种投射是否安全。

处理这种情况的更好方法是什么?

3 个答案:

答案 0 :(得分:5)

您遇到了“是一个”问题。

如果您已将zebra分配给animal,那么就不存在任何问题,因为zebra的班级是Zebra,“是”Animal 1}}。

但是,根据您正在做的事情,您将animal分配给zebra,但animal属于超级类Animal。 “是一个”测试失败,但是一个简单的演员:

zebra = (Zebra *)animal;

负责编译器警告。是的,这是安全的。

这是一种更现代的做同样事情的方式。顺便说一下,由于在最后一行-objectAtIndex:返回id,因此不会出现上述问题:

NSUInteger index = [zoo indexOfObjectPassingTest:^BOOL(Animal *animal, NSUInteger idx, BOOL *stop) {
    return ([animal isMemberOfClass:[Zebra class]] && animal.alive);
}];
Zebra *zebra = (index != NSNotFound) ? [zoo objectAtIndex:index] : nil;

请注意,我确实从id objAnimal *animal调整了该块的一个参数;如果您知道您的集合仅包含对Animal实例的引用,那么您当然可以这样做。

答案 1 :(得分:3)

绝对是在Objective-C中做到这一点的方法。如果您首先检查它是您的铸造类型,那么它非常安全。即使它“键入”其他内容,isMemberOfClass也会使用运行时来报告真正的内容。

答案 2 :(得分:1)

执行相同任务的另一种方法。

[zoo enumerateObjectsusingBlock:^(id obj, NSUInteger index, BOOL *stop){
    if ([obj isMemberOfClass:[Zebra class] && animal.alive){
        zebra = (Zebra *)animal;
        *stop = YES;
    }
}];
顺便说一下,这种铸造方式是安全的。