在检查类型之前将id存储到实际类指针中是否安全

时间:2013-09-12 05:52:23

标签: objective-c

我有很多看起来像这样的代码:

id myObjectRaw = getObject();
if(![myObjectRaw isKindOfClass:[MyClass class]]) return nil;
MyClass * myObject = myObjectRaw;
...

这里id getObject()可以返回几种对象。但是上面的代码对我来说很笨拙。写这个是安全的吗?

MyClass * myObject = getObject();
if(![myObject isKindOfClass:[MyClass class]]) return nil;
...

编译器没有抱怨,但如果getObject返回与MyClass无关的对象,我不确定我是不是在处理未定义的行为。

(不,我不能使用超类或接口,因为我实际上无法控制所有返回的类。)

4 个答案:

答案 0 :(得分:5)

你可以做到。什么都没有定义。唯一的危险是,如果类型错误并且您忘记检查类型,则可能由于无法识别的选择器异常而崩溃。

在已编译的代码中,idMyClass *NSString *没有区别,它们只是指向ObjC对象的指针。

答案 1 :(得分:2)

只要所有类型的返回对象符合NSObject协议(从NSObject类继承的类),就可以安全地使用isKindOfClass:方法。

因此,请确保getObject()方法仅返回从NSObject继承的objective-c类

修改

虽然编译器很好用,但@Eiko提到有人阅读代码可能会认为isKindOfClass:检查是不必要的。最好使用前面的代码让读者知道getObject()也可能返回其他类型的对象。

答案 2 :(得分:2)

两个版本都可以使用。第一个感觉很笨,但第二个也存在问题:将某些东西放入特定类型的变量中意味着知道它的类型,并且检查看似已知的东西的类已经看起来多余了。如果有人(可能是你)明年查看该代码,他可能会发现班级检查是多余的并将其删除。

我一直处于类似的情况,我使用了一个帮助方法,它给出了一个正确的类型结果或者没有,即

-(Rectangle)getRectangleObject {
   id data = getObject();
   if ([data isKindOfClass:[Rectangle class]]) return data;
   return nil;
}

这简化了代码并清楚地传达了意图。 如果需要多种不同的类型检查,可以使用多种方法,或者将类传递给此辅助方法。

答案 3 :(得分:0)

当你使用id myObjectRaw时,你没有定义什么类型的对象myObjectRaw,因此编译器不知道MyClass * myObject = getObject();是否是有效的操作。编译器假定您知道自己在做什么。如果getObject()返回的对象与MyClass不同,或者它不是它的子类,那么您的应用可能会崩溃。这是运行时错误。

如果getObject()返回不同的对象,您应该期望至少有一个可以返回的对象类型的对象。如果需要处理不同的对象,您可以始终使用if-else-if指令,如:

id myObjectRaw = getObject();

if([myObjectRaw isKindOfClass:[MyClass1 class]])
{
    MyClass1 objectClass1 = myObjectRaw;
}
else if([myObjectRaw isKindOfClass[MyClass2 class]])
{
    MyClass2 objectClass2 = myObjectRaw;
}

但是,如果返回的对象是MyClass2对象,并且此类是MyClass1的子类,则第一个条件将为true。因此,该对象将保存为MyClass1对象。如果是这种情况,您需要建立优先级并将它们相应地放在嵌套的if-else-if语句中。