【问题标题】:for loops - Object type disregarded?for 循环 - 忽略对象类型?
【发布时间】:2011-10-29 07:39:24
【问题描述】:

我有时喜欢将 IB 元素组织到 NSArrays 中,主要是为了帮助我组织元素。大多数情况下,不同类别的对象会彼此组成同一个数组。虽然这种 是一种方便的组织方式,但我似乎无法理解为什么如果我有这样的数组:

NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil];

为什么当我像这样放置for 循环时收到“不响应选择器”消息:

for (UITextField *text in array) {
    [text setText:@""];
}

for 循环似乎传递了不属于 UITextField 类的对象。

如果指定数组中的所有对象都通过循环,那么声明对象的类有什么意义?

编辑仅供参考,这是我目前的处理方式:

for (id *object in array) {
    if ([object isMemberOfClass:[UITextField class]]) {
        foo();
    } else if ([object isMemberOfClass:[UISegmentedController class]) {
        bar();
    }
 }

【问题讨论】:

  • id 已经是指针类型。 99.9% 的时间,您想使用普通的 id 类型,而不是指向 id* 的指针。

标签: iphone objective-c for-loop nsarray


【解决方案1】:

如果指定数组中的所有对象都通过循环,那么声明对象的类有什么意义?

类名只是为了让编译器知道它应该找到什么。这允许它尝试找出它应该期望您调用哪些方法以及您可能如何处理该对象。这与将int 传递给采用float 的方法的想法相同。该方法不会忽略整数 - 它假设您传递了正确的类型。你只是给了这个构造比它应得的更多的功劳:

for (UITextField *text in array)

它只是没有那个功能。你现在的处理方式是正确的。

【讨论】:

    【解决方案2】:

    当你这样做时

    for (UITextField *text in...
    

    数组中的对象指针被转换为 UITextField* 类型 - 因此,如果对象实际上不是 UITextField,那么如果您尝试调用 UITextField 方法,可能会发生各种奇怪的事情。

    所以改为使用 id 类型(不需要 *,顺便说一句):

    for (id obj in array)
    

    然后像你一样检查类型并调用适当的方法。或者,过滤数组以仅获取特定类型的对象,然后仅查看该类型:

    for (UITextField* text in [array filteredArrayUsingPredicate:...])
    

    编辑:这是构建类过滤谓词的方法:

    Is it possible to filter an NSArray by class?

    【讨论】:

    • 对象不会转换为新类型——指针是。在发送消息时,指针的类型无关紧要。如果您愿意,您可以使用NSWindow* 类型的指针将-appendString: 发送到一个对象,只要该指针确实指向NSMutableString 的实例,它就可以正常工作。 (您可能会收到编译器警告,但它会起作用。)但是,如果指针指向窗口,您当然会在运行时收到错误,除非您采取措施防止这种情况发生。
    • 你当然是对的,我已经相应地修改了我的答案。
    • 需要编辑的部分是“如果对象实际上不是 UITextField,则可能会发生各种奇怪的事情......”。如果对象实际上不是 UITextField,您将得到一个未实现的选择器异常。
    • “对象无法识别选择器”。但是,如果 一个具有相同名称的方法(如 setText: - 相当通用),它实际上会在没有异常但可能不会完全符合预期的意义上工作。这就是为什么我把它归为“奇怪的事情”。
    • 我发现使用特定类型(如 UITextField*)而不是 id 更方便,因为编译器将在该循环内检查我的方法调用。当然,在调用任何方法之前,必须检查以确保它确实是正确类的对象。
    【解决方案3】:

    您确定您在运行该代码时没有收到错误吗? “不响应选择器”消息是运行时错误,而不是编译时错误。编译器不知道数组中的对象是否实现了-setText:,但是当您实际将该消息发送到UISegmentedControl 的实例时,您肯定会收到错误消息。

    另一种可能性是你有一个名为UISegmentedController 的类,它确实有一个-setText: 方法。实现多部分条形图外观用户界面小部件的类的名称是UISegmentedControl。所以要么你展示的代码不是真实的,经过测试的代码,要么你有一个我们不知道的类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 2021-12-19
      • 2014-07-24
      • 1970-01-01
      • 2018-03-02
      • 1970-01-01
      相关资源
      最近更新 更多