3

Animal是一个具有BOOL名为 的属性的类aliveMonkey,Zebra并且Walrus是 的子类Animal。如果我有一个包含 , 和 的混合实例的NSArray被调用实例,并且我想找到第一个活动的实例,我可能会执行以下操作:zooMonkeyZebraWalrusZebra

Zebra *zebra; 
for (Animal *animal in zoo) {
    if ([animal isMemberOfClass:[Zebra class]] && animal.alive) {
        zebra = animal;
        break;
    }
}

问题是编译器在我设置时抱怨指针类型不兼容zebra = animal。如果我像这样进行一些转换,zebra = (Zebra *)animal它似乎可以工作,但我不确定这种转换在 Objective-C 中是否安全。

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

4

3 回答 3

5

您遇到了“是”问题。

如果您一直分配zebraanimal,则不会有问题,因为 is 的类zebraZebra即 "is a" Animal

但是,随着您所做的事情,您分配animal给超类zebra,但animal属于 class Animal。"is a" 测试失败,但是一个简单的转换:

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,您当然可以这样做。

于 2013-08-27T13:50:01.580 回答
3

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

于 2013-08-27T12:17:22.900 回答
1

完成相同任务的另一种方法。

[zoo enumerateObjectsusingBlock:^(id obj, NSUInteger index, BOOL *stop){
    if ([obj isMemberOfClass:[Zebra class] && animal.alive){
        zebra = (Zebra *)animal;
        *stop = YES;
    }
}];

顺便说一句,这种铸造方式是安全的。

于 2013-08-28T06:42:22.973 回答