2012-07-16 24 views
5

通过调用isKindOfClass检查类的类型是否更合适:或者通过仅检查它是否支持您通过respondsToSelector查找的方法来执行“duck typing”方法:?Objective-C:检查类的类型,最好使用isKindOfClass或respondsToSelector?

这里是我想的,两种方式编写代码:

for (id widget in self.widgets) 
{ 
    [self tryToRefresh:widget]; 

    // Does this widget have sources? Refresh them, too. 
    if ([widget isKindOfClass:[WidgetWithSources class]]) 
    { 
     for (Source* source in [widget sources]) 
     { 
      [self tryToRefresh:source]; 
     } 
    } 
} 

或者:

for (id widget in self.widgets) 
{ 
    [self tryToRefresh:widget]; 

    // Does this widget have sources? Refresh them, too. 
    if ([widget respondsToSelector:(@selector(sources))]) 
    { 
     for (Source* source in [widget sources]) 
     { 
      [self tryToRefresh:source]; 
     } 
    } 
} 
+0

检查这个线程http://stackoverflow.com/questions/4913055/iphone-is-using-iskindofclass-considered-bad-practice-in-any-way – 2012-07-16 18:37:07

+0

需要注意的是,在一般情况下,动态不鼓励检查班级的类型。委托模式之外的选择器响应也一样。 – bbum 2012-07-16 19:57:47

回答

2

检查可能是一个警告,您即将做出一个hackish解决方案。小部件已经知道他的课程和他的选择器。

所以第三个选择可能是考虑重构。将此逻辑移至[widget tryToRefresh]可能会更清晰并允许将来的小部件实现额外的幕后逻辑。

+0

所有好的答案,但这一个,对我来说其实是正确的。我能够重新执行并彻底摆脱这些代码! – 2012-07-17 18:36:06

6

这要看情况!

我的经验法则是,这仅仅是为了我,还是将它传递给其他人?

在你的例子中,respondsToSelector:没有问题,因为你只需要知道你是否可以发送消息的对象,所以你可以对结果做些什么。这个班并不是那么重要。另一方面,如果您要将该对象传递给其他代码段,您不一定知道它将要发送的消息。在这些情况下,你可能会投射物体以传递它,这可能是你在投射它之前检查它是否真的isKindOfClass:的线索。

要考虑的另一件事是歧义; respondsToSelector:告诉你一个对象会响应一条消息,但是如果该对象返回一个不同于你期望的类型,它可能会产生一个误报。例如,一个对象,声明的方法:当您尝试在一个for循环中使用它的返回值

- (int)sources; 

会通过respondsToSelector:测试,但随后产生异常。

这种情况发生的可能性有多大?这取决于你的代码,你的项目有多大,有多少人正在编写针对你的API的代码等等。

5

它稍微更习惯使用目标C使用respondsToSelector:。目标C具有高度的动态性,因此您的设计时间对类结构的假设可能不一定在运行时保持水分。 respondsToSelector:通过给你一个查询类的最常见原因的快捷方式来获取它 - 它是否执行一些操作。

一般来说,如果围绕几个同样吸引人的选择存在歧义,那么请注意可读性。在这种情况下,这意味着思考意图。你关心,如果它是特别是WidgetWithSources,或者你真的只是在乎它有一个sources选择器?如果是后者,则使用respondsToSelector:。如果前者可能在某些情况下使用isKindOfClass.可读性,则表示您不要求读者在WidgetWithSources的类型对等和需要调用sources之间建立连接。 respondsToSelector:为读者提供了连接,让他们知道您的实际意图。这是对你的程序员的一种善意。

编辑:@ benzado的答案很好地吻合。

3

从@Tim & @benzado很好的答案,这里是对主题的变化,先前覆盖2箱子第一:

  • 如果在某些时候,你有没有可能有不同类的引用,并需要他们不同的是,这可能是isKindOfClass:的一种情况。例如,颜色可能存储在首选项中,作为NSColorNSData序列化或具有其中一个标准名称的NSString值;获取NSColor的值在这种情况下isKindOfClass:上的对象返回可能是合适的。
  • 如果你有一个类的引用,但不同版本它随着时间的推移支持不同的方法,然后考虑respondsToSelector:例如,许多框架类在OS的更高版本中添加新的方法,Apple的标准建议是检查对于使用respondsToSelector:(而不是OS版本检查)的这些方法。
  • 如果你有不同类别的参考,如果他们坚持一些非正式协议那么你正在测试:

    1. 如果是这样的代码,你控制,你可以切换到正式协议然后使用conformsToProtocol:作为测试。这具有测试类型而不仅仅是名称;否则
    2. 如果是这样的代码你不用管,然后使用respondsToSelector:,但我们知道这是测试具有相同的方法存在,不在于它采用相同类型的参数