在 Switch Case 中声明 UI 个对象
Declaring UI Objects in Switch Cases
我已经阅读了 switch cases 的范围,jump labels 等等,但是这里建议的解决方案似乎暗示添加花括号可以解决这个问题.但是,这似乎仍然不起作用:
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,因此错误:
属性 'text' 未在 '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.
是的,只需在切换之前声明一个通用 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));
问题是您的 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) {
}
Objective-C 中的范围规则非常简单。任何时候输入一对大括号,都会进入一个新的范围级别。在该范围内声明的任何变量仅存在于该范围内。当你退出大括号时,变量不复存在。
switch 中的个别情况不需要大括号,因此它们不定义局部范围级别,但整个 switch 语句 使用大括号,等等它确实定义了一个本地范围。在 switch 语句的大括号内声明的任何变量在大括号外都不存在。
当您进入新的范围级别时,您可以访问在您的 parent 范围内声明的所有内容。
你没有说清楚你想做什么。我 THINK
你想要做的是有一个 parent class 的变量,然后把来自 subclasses 的新 objects 放入其中,并且仍然可以访问 child class.
的独特属性
如果您声明一个基数 class 的变量,您可以将作为该类型的子class 的任何 object 分配给该变量。
如果要访问子class的属性,则必须将变量转换为适当的类型:
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;
}
编辑
我发现转换语法很难打字,而且会让人感到困惑。有时候创建一个新的object实际类型的临时变量,做任何你需要做的事情,然后把它赋值给目标变量会更清楚,像这样:
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语句之外,你不会知道object控件变量包含的是哪种类型,所以你将只能访问UIView基类的属性class,除非您将变量转换为特定类型,如上所示。
(请注意,上面的名称 "control" 是一个错误的选择,因为标签不是控件。最好使用像 "aView" 这样的名称,它暗示了常见的 class变量中可能存在的所有 object。)
将控件声明为 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`
希望对您有所帮助:)
我已经阅读了 switch cases 的范围,jump labels 等等,但是这里建议的解决方案似乎暗示添加花括号可以解决这个问题.但是,这似乎仍然不起作用:
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,因此错误:
属性 'text' 未在 '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.
是的,只需在切换之前声明一个通用 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));
问题是您的 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) {
}
Objective-C 中的范围规则非常简单。任何时候输入一对大括号,都会进入一个新的范围级别。在该范围内声明的任何变量仅存在于该范围内。当你退出大括号时,变量不复存在。
switch 中的个别情况不需要大括号,因此它们不定义局部范围级别,但整个 switch 语句 使用大括号,等等它确实定义了一个本地范围。在 switch 语句的大括号内声明的任何变量在大括号外都不存在。
当您进入新的范围级别时,您可以访问在您的 parent 范围内声明的所有内容。
你没有说清楚你想做什么。我 THINK
你想要做的是有一个 parent class 的变量,然后把来自 subclasses 的新 objects 放入其中,并且仍然可以访问 child class.
如果您声明一个基数 class 的变量,您可以将作为该类型的子class 的任何 object 分配给该变量。
如果要访问子class的属性,则必须将变量转换为适当的类型:
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;
}
编辑
我发现转换语法很难打字,而且会让人感到困惑。有时候创建一个新的object实际类型的临时变量,做任何你需要做的事情,然后把它赋值给目标变量会更清楚,像这样:
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语句之外,你不会知道object控件变量包含的是哪种类型,所以你将只能访问UIView基类的属性class,除非您将变量转换为特定类型,如上所示。
(请注意,上面的名称 "control" 是一个错误的选择,因为标签不是控件。最好使用像 "aView" 这样的名称,它暗示了常见的 class变量中可能存在的所有 object。)
将控件声明为 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`
希望对您有所帮助:)