gpt4 book ai didi

ios - 检查 NSDictionary 中的键 - 不使用 bool NSNumber 作为值 @iOS8

转载 作者:行者123 更新时间:2023-11-29 10:34:25 26 4
gpt4 key购买 nike

我刚刚在 iOS 8 (@ 8.1.1 & 8.1.2) 上发现了 NSDictionary 的一个奇怪问题。我可以测试的所有其他设备(包括 (8.1) 模拟器)都没有遇到这个问题。
在 iOS8 中,检查 NSDictionary 对象中的键在以下情况下无法按预期工作:

  1. key 的值是一个用 bool 值 YES 初始化的 NSNumber 对象
  2. dict[@"testKey"] 或 [dict objectForKey:@"testKey"] 用于检查key是否存在
  3. 检查结果存入BOOL变量

首先看下面的示例代码(我知道你可以将整个检查机制压缩在一行中——这只是为了说明问题):

-(void) doSomethingDependingOn:(BOOL)foo andBar:(BOOL)bar andAttr:(NSDictionary*)dict {
BOOL doAction = NO;

if (foo) {
doAction = dict[@"trigger1"]; // check if key exists in dictionary
}

if (bar) {
doAction = dict[@"trigger2"]; // check if key exists in dictionary
}

if (doAction) {
// do something
}
}

此代码运行良好 - 除了它在真正的 iOS 8 设备(而非模拟器)上运行并且选中键的值是一个 NSNumber 对象并用 bool 值 YES 初始化的情况。在这种情况下,key-exists-check FAILS——这意味着变量 doAction 被设置为 NO,尽管该 key 存在并且您找到了该键的完美对象( bool 值 YES 或整数 1 的 NSNumber)。
对我来说,这似乎是一个 iOS 8 错误。

您可以使用以下代码验证这一点:

NSDictionary *dict = @{@"key1" : [NSNumber numberWithBool:YES], @"key2" : @"value2"};
BOOL opt_1 = [dict objectForKey:@"key1"];
BOOL opt_2 = dict[@"key1"];
BOOL opt_3 = ([dict objectForKey:@"key1"] ? 1 : 0);

if ([dict objectForKey:@"key1"]) NSLog(@"1. OK");
if (dict[@"key1"]) NSLog(@"2. OK");

if (opt_1) NSLog(@"opt_1 OK");
if (opt_2) NSLog(@"opt_2 OK");
if (opt_3) NSLog(@"opt_3 OK");

NSLog(@"check ref: [NSNumber numberWithBool:YES] -> %p\tdict[@\"key1\"] -> %p",[NSNumber numberWithBool:YES],dict[@"key1"]);

输出@iOS8:

- 1. OK
- 2. OK
- opt_3 OK
- check ref: [NSNumber numberWithBool:YES] -> 0x3303b900 dict[@"key1"] -> 0x3303b900

输出@其他设备:

- 1. OK
- 2. OK
- opt_1 OK
- opt_2 OK
- opt_3 OK
- check ref: [NSNumber numberWithBool:YES] -> 0x3eb319f0 dict[@"key1"] -> 0x3eb319f0

我对此没有任何解释。是错误吗?

编辑:为指向值的指针引用添加打印输出(值检查)

已解决:感谢 CRD!这是我的代码中的错误,而不是 iOS 8 中的错误 - 令人惊讶。 ;-) BOOL keyCheck = [dict objectForKey:@"key1"]; 是检查字典中键是否可用的无效方法。就是这样!你生活,你学习,你编码,你学习。感谢大家的意见!

最佳答案

好的,代码中有一个错误,它不是一个错误(虽然有些人可能会争辩说它是一个语言错误,但那是另一个问题;-))

在 C 中,条件语句接受一个被测试为“不等于 0”的表达式,并且有多种类型 - 数字类型(包括 charBOOL) 和指针类型 - 可以与 0 进行比较。对于指针,0 表示空指针常量,通常在 Obj-C 中表示为 nil。所以你的声明:

BOOL opt_3 = ([dict objectForKey:@"key1"] ? 1 : 0);

在语言规范中直接等同于:

BOOL opt_3 = ([dict objectForKey:@"key1"] != nil ? 1 : 0);

同样在C语言中,指针可以转换为整数,不同大小的整数类型可以相互转换。如果转换为更大的类型,则转换为隐式,否则为显式 - 但是编译器可能只是在后一种情况下发出警告并编译代码,就好像转换是明确的。这是 Xcode 对您的两个语句执行的操作:

BOOL opt_1 = [dict objectForKey:@"key1"];
BOOL opt_2 = dict[@"key1"];

产生警告,BOOL 类型小于对象引用,但可以编译。您可以放入一个显式的 (BOOL) 转换来消除警告,但这不会修复错误。

问题来自于 C 如何进行从较大类型到较小类型的转换 - 它只是截断 - 无论结果的数学/逻辑正确性如何。所以上面两个语句所做的是将指针值的最低有效字节分配给 BOOL 变量(因为 BOOL 是一个字节)。

现在查看您添加到问题中的指针值。在非 iOS8 设备上,该值为 0x3eb319f0,被截断为一个字节的是 0xf0,并且被解释为 BOOL 的值为真(任何非-零为真)。

在 iOS8 上,该值为 0x3303b900,截断为一个字节为 0x00,即 BOOL NO .

这些值当然是“随机的”——你可能会得到相反的结果,而 iOS8 显然可以正常工作,或者混合使用。实际上,程序不同部分的相同测试可能会产生不同的结果。这也解释了为什么代表 1NSNumber 可能会给出与代表 YES 的结果不同的结果。

要修复您的代码,只需将其更改为:

BOOL opt_1 = [dict objectForKey:@"key1"] != nil;
BOOL opt_2 = dict[@"key1"] != nil;

它应该可以工作。

HTH

关于ios - 检查 NSDictionary 中的键 - 不使用 bool NSNumber 作为值 @iOS8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27845668/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com