在Switch Case中声明UI对象

时间:2015-05-21 08:39:10

标签: ios objective-c scope switch-statement declaration

我已经阅读了关于切换案例的范围,跳转标签以及所有这些,但是这里的建议解决方案似乎暗示添加花括号会绕过这个问题。但是,这似乎仍然不起作用:

switch (objectType) {

  case label:   //label is an integer constant
    NSLog(@"statement before declaration");
    UILabel *control = [[UILabel alloc] init];       //no error
    break;

  case button:  //button is an integer constant
    {
      UIButton *control = [[UIButton alloc] init];   //no error
    }
    break;    

  default:
    break;
}

// error when trying to use the *control* variable,
// Use of undeclared identifier 'control'

有没有办法用switch语句完成这个?

2015年5月23日:尝试了许多不同的方法,但没有成功。

编辑:实施Cyrille建议的解决方案时出错:

UIView *control = nil;
switch (objectType)
{
  case label:  //button is an integer constant
    {
      control = [[UILabel alloc] init];   //no error

      //error: property 'text' not found on object of type 'UIView *'
      control.text = @"Something...";     
    }
    break; 

  default:
    break;
}

显然,即使从 UIView 重铸到 UILabel 之后,该对象也没有继承 UILabel 的所有属性,因而错误:

在'UIView *'类型的对象上找不到属性'文字'

即使Zil建议使用(UILabel*)[[UILabel alloc]init];类型作为前缀也不起作用。

有没有人让这个工作?

DUNCAN C的解决方案。 (见下面接受的答案)

    UIView *control = nil;
    switch (objectType)
    {
        case label:  
            control = [[UILabel alloc] init];
            ((UILabel *)control).text = @"Something...";     
            break; 

        default:
            break;
    }

    // UI object instantiated inside switch case recognised!
    ((UILabel *)control).textColor = [UIColor redColor];

谢谢Duncan C.

4 个答案:

答案 0 :(得分:2)

Objective-C中的范围规则非常简单。每次输入一对花括号时,都会输入一个新的范围。在该范围内声明的任何变量仅存在于该范围内。退出大括号时,变量不再存在。

交换机内的个别情况不需要支撑,因此它们不会定义本地范围的范围,但整个switch语句确实使用大括号,所以它确定了本地范围。在switch语句的括号内声明的任何变量都不存在于大括号之外。

当您输入新的范围级别时,您可以访问父范围中声明的所有内容。

你不能完全清楚自己想要做什么。我THINK你想要做的是拥有一个父类的变量,然后在其中放入来自子类的新对象,并且仍然可以访问子类的唯一属性。

如果声明基类的变量,则可以将任何作为该类型子类的对象分配给变量。

如果要访问子类的属性,则必须将变量强制转换为适当的类型:

UIView *control = nil;
switch (objectType)
{
  case label:  
    control = [[UILabel alloc] init];   //no error

    ((UILabel *)control).text = @"Something...";     
    break; 
  case button: 
    control = [UIButton buttonWithType: UIButtonTypeSystem];
    [((UIButton *)control) setTitle: "Foo" forState: UIControlStateNormal];
  default:
    break;
}

修改

我发现转换语法很难输入,而且会让人感到困惑。有时可以更清楚地创建对象的实际类型的新临时变量,做你需要做的任何事情,然后将它分配给目标变量,如下所示:

UIView *control = nil;
switch (objectType)
{
  case label:  
    UILabel *aLabel = [[UILabel alloc] init];   //no error

    aLabel.text = @"Something...";   
    aLabel.someOtherProperty = someOtherValue;
    control = aLabel;  
    break; 
  case button: 
    UIButton aButton = [UIButton buttonWithType: UIButtonTypeSystem];
    [aButton setTitle: "Foo" forState: UIControlStateNormal];
    control = aButton
  default:
    break;
}

在switch语句之外,你不知道控件变量包含哪种类型的对象,所以你只能访问UIView基类的属性,除非你强制转换变量到特定类型,如上所示。

(注意名称" control"上面是一个糟糕的选择,因为标签不是一个控件。最好使用类似" aView"这意味着共同的类可能在变量中的所有对象。)

答案 1 :(得分:1)

是的,只需在切换前声明通用control

UIView *control = nil;
switch (objectType) {

  case label:   //label is an integer constant
    NSLog(@"statement before declaration");
    control = [[UILabel alloc] init];       //no error
    break;

  case button:  //button is an integer constant
    {
      control = [[UIButton alloc] init];   //no error
    }
    break; 

  case other:
    control = [[UIView alloc] init]; // works too   

  default:
    break;
}

NSLog(@"Control frame is %@", NSStringFromCGRect(control.frame));

答案 2 :(得分:1)

将控件声明为UIView *后,如果您尝试访问UIView上不存在的属性,则会出现错误。

然而,正如Duncan C所说,你总是可以使用点表示法强制转换和访问该属性,例如:

((UILabel *)control).text = @"This Works";

然后访问值

NSLog(@"Control text: %@", ((UILabel *)control).text);

我的目的是使用不同的方法,将控件声明为id并使用Objective-C方法调用。您需要确保控件响应您尝试调用的选择器。如果您想在尝试访问选择器时保护应用程序崩溃,可以使用respondsToSelector:方法。 我的建议的一个例子:

unsigned objectType = 1;
id control = nil;

switch (objectType) {

    case 1:   //label is an integer constant
        NSLog(@"statement before declaration");
        control = [[UILabel alloc] init];       //no error
        [control setText:@"a"];
        break;

    case 2:  //button is an integer constant
    {
        control = [[UIButton alloc] init];   //no error
    }
        break;

    default:
        break;
}

NSLog(@"Control text %@", [control text]);

结果是:

2015-05-23 13:12:06.840 test2[46589:12231454] statement before declaration
2015-05-23 13:12:06.841 test2[46589:12231454] Control text `a`

希望有所帮助:)

答案 3 :(得分:0)

问题是你的control变量是在switch语句的范围内声明的,然后你试图在外面使用它:

UILabel *controlLabel = nil;
UIButton *controlButton = nil;

    /*
    I've defined two variables but you could do the same with one like so
    id control = nil;
    or
    UIControl *control = nil;
    */

switch (objectType) {

  case label:   //label is an integer constant
    NSLog(@"statement before declaration");
    controlLabel = [[UILabel alloc] init];       //no error
    break;

  case button:  //button is an integer constant
    {
      controlButton = [[UIButton alloc] init];   //no error
    }
    break;    

  default:
    break;
}

if (controlLabel) {

} else if (controlButton) {

}