ViewController.mm中的以下代码将在64位环境中成功编译(没有任何警告或错误)。
- (void)viewDidLoad {
[super viewDidLoad];
BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
NSLog(@"%d", var);
}
但是当我将运行目标更改为32位设备(例如iPhone 5)时,它显示出如下错误:
Cannot initialize a variable of type 'BOOL' (aka 'signed char') with an rvalue of type 'id _Nullable'
我确实知道这项工作很麻烦,但是为什么在第一种情况下允许这样做?
答案 0 :(得分:3)
对于64位iOS,BOOL
类型使用C99 _Bool
类型(有时也可以作为bool
使用)。将该类型定义为仅具有两个值,即0或1。将其他任何值分配给该类型的变量,将使其采用值1。(即,所有非零值都变为1。)
因此,赋值不会截断按位值,可能会将非零值转换为零。因此,从某种意义上讲它是“安全的”,没有警告的理由。 (对于一个天真的开发人员,仍然不感到惊讶,因为他不了解对象的指针与其值之间的区别,正如其他答案所解决的那样,但这是另一回事。)
答案 1 :(得分:1)
该错误表明您正在将对象分配给类型为BOOL
的变量。要解决该问题,您需要使用BOOL
将objectForKey:返回的对象转换为boolValue
变量。
BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"] boolValue];
答案 2 :(得分:1)
您的代码:
AttributeError: Tensor.name is meaningless when eager execution is enabled.
正在将对象的地址分配给某种大小的int ...
这几乎总是不是您想要的。您可能想要:
BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
如果您确实想根据该对象的存在进行分配,则可以执行以下操作:
BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"]boolValue];
原因是,如果地址的后8位全部为0,则它可能是有效对象,但将是错误值,这是截断分配的结果。
BOOL var = !![[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
打印:int main(int argc, const char * argv[]) {
BOOL b = 2;
if (b == YES)
{
NSLog(@"I guess you are right");
}else{
NSLog(@"nope");
}
答案 3 :(得分:1)
起作用的原因有很多,其中许多历史性的东西只存在,因为它曾经是那样。
bool
是一种相对较新的类型。如果您查看旧的C代码,通常会发现它们只是使用int
,或者像Objective-C编译器一样声明自己的Bool
,BOOL
或{{1 }}类型。
返回最初定义Objective-C时,他们为Boolean
类型使用了最小的类型(signed char
)。
C BOOL
语句始终允许使用指针作为其条件,以测试指针不是if
(或ObjC情况下的NULL
)。
将nil
添加到C标准时,它基本上被定义为“ bool
所采用的类型”,因此必须具有所有相同的行为,包括允许您提供一个指针,该指针应为预期的布尔值,如果为if
则为false
,否则为nil
。
Apple无法将旧计算机上的true
更改为BOOL
,因为它会更改bool
会返回@encode()
的符号,并且使得旧程序无法与新库链接到同一进程(反之亦然)。
当64位iOS到来时,许多数据类型已经改变了大小,因此Apple可以安全地将BOOL
更改为BOOL
,因为不需要任何旧程序。能够在与新库相同的内存空间中运行。一切都是新的。
因此,在将bool
的新定义为BOOL
的平台上,您会遇到C的向后兼容功能,即让您检查bool
指针。在较旧的平台上,NULL
被定义为BOOL
,显然不适合指针,并且没有特殊的指针,因此会产生警告。