【问题标题】:Obj-C introspection: how to avoid casting all the time?Obj-C 内省:如何避免一直强制转换?
【发布时间】:2013-04-25 13:52:10
【问题描述】:

大家好, 我一直在研究 Objective-C 中执行对象自省的一些枚举例程。特别是,在调整它们的属性和/或调用它们的方法之前,我正在快速枚举 NSSet 并确保其中的对象属于 BBBallView 类(我同意这是一个相当不幸的名称)。

然而,为了让解析器和编译器满意,我最终在每一行都将对象转换为它的类;此外,为了访问其属性,对象的强制转换必须在括号中,否则点符号将不起作用。这会导致代码有些混乱:

for (id otherBall in self.gameField.subviews) {
    if ([otherBall isKindOfClass:[BBBallView class]]) {
        if ( !((BBBallView *)otherBall).isEnlarged ) {
            CGRect otherFrame = ((BBBallView *)otherBall).frame;
            /* ... */
        }
    }
}

有没有办法告诉编译器“此时我知道otherBallBBBallView,所以不要再告诉我它不响应这些选择器和属性”?这样一来,你就可以写:

for (id otherBall in self.gameField.subviews) {
    if ([otherBall isKindOfClass:[BBBallView class]]) {
        if ( !otherBall.isEnlarged ) {
            CGRect otherFrame = otherBall.frame;
            /* ... */
        }
    }
}

等等。

我尝试了otherBall = (BBBallView *)otherBall,但“默认情况下无法在 ARC 中修改快速枚举变量”。将枚举变量更改为__strong id 可以修复它,但无济于事,因为任何后续行都会给出错误,例如“在'const __strong id'类型的对象上找不到属性isEnlarged”,所以我回来了平方一。

我什至不确定为什么会发生这种情况:当变量的类型为id 时,编译器不应该置身事外吗?无论如何,在需要对对象的属性执行多次计算的方法中,整个考验尤其混乱,因为所有这些括号很快就会变得不可读。

有没有办法解决这个问题?

提前致谢!

【问题讨论】:

  • 一般来说,重度内省模式是一种代码味道。集合通常不应包含异构类型。此外,拥有一个提供基本服务的抽象类,以及细化行为的特定子类,可以避免大量的自省。

标签: objective-c casting enumeration introspection


【解决方案1】:

您可以创建具有正确类型的本地临时文件,也可以不使用点表示法。

  1. 当地温度

    for (UIView *view in self.gameField.subviews) {
      if ([view isKindOfClass:[BBBallView class]]) {
        BBBallView *ballView = view;
        if (!ballView.isEnlarged) {
          CGRect otherFrame = ballView.frame;
          /* ... */
        }
      }
    }
    
  2. 不要使用点符号

    for (id otherBall in self.gameField.subviews) {
      if ([otherBall isKindOfClass:[BBBallView class]]) {
        if ( ![otherBall isEnlarged]) {
          CGRect otherFrame = [otherBall frame];
          /* ... */
        }
      }
    }
    

如果我只做几件事,我会很想不使用点符号。如果阅读起来很尴尬并且访问量很大,那么我会考虑本地临时

【讨论】:

  • 我只是想写一个完全相同的答案......但你打赌我! +1 :)
  • 您说得有道理(不是双关语!),使用临时局部变量可能是提高可读性的最佳方式。我宁愿坚持使用点表示法,主要是为了代码的一致性。我不知道为什么我没有想到它,也许在我的脑海里我认为我在浪费内存——但它只是另一个指针,而不是副本,所以它是局部变量!简单有效。谢谢。 :)
【解决方案2】:

我认为您正在苦苦挣扎,因为逻辑似乎放错了地方。语言与你抗争是因为你的程序结构,而不是因为语言有缺陷。

子视图的父类型真的合适吗?还是您将圆形物体塞入方形中,违反了 Liskov 替换原则?

您还可以问,从外部检查 BBBallView 逻辑的内部是否真的合适?你能把逻辑移到适当的类吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多