我有以下代码:
// ...
[self performSelectorInBackground:@selector(mySel:) withObject:@YES];
}
// ...
- (void) mySel:(BOOL)suppressUserAlerts
{
NSError*error;
[obj doActionWithError:&error];
if (!suppressUserAlerts && error) // line with breakpoint
{
[self alertOfError:error];
}
// ...
现在,即使我传入@YES
,也始终会调用alertOfError:
。所以,当然,我调试了它并添加了一些观察到的表达式和断点,我发现这是胡说八道:
所以,令人困惑,我问:为什么suppressUserAlerts
YES
和!suppressUserAlerts
true
?更重要的是,我如何获得我想要的价值?
答案 0 :(得分:2)
@timgcarlson在他的更正中是正确的。
然而,回答你的问题:
您实际上是通过@YES
传递对象。如果您现在有声明
if (!supressUserAlerts) {
您实际上正在测试对象的不存在(相当于supresseUserAlerts == nil
)。
BOOL
声明更像是仅影响调试器的强制转换。
所以你的陈述永远是真的,因为@YES
创建了一个不等于nil
的对象。
修改的
以正确的方式解决您的错误:
// ...
[self performSelectorInBackground:@selector(mySel:) withObject:@YES];
}
- (void)mySel:(NSNumber *)suppressUserAlerts {
NSError *error;
[obj doActionWithError:&error];
if (![suppressUserAlerts boolValue] && error) {
[self alertOfError:error];
}
// ...
编辑II
我认为你在调试器中看到的只是输出标量布尔值(由!
前缀创建)与对象bool的对比方式。
答案 1 :(得分:1)
这一行:
[self performSelectorInBackground:@selector(mySel:) withObject:@YES];
正在传递NSNumber
个实例。这里有必要使用对象而不是标量BOOL
值,因为-performSelectorInBackground:withObject:
只能处理对象类型的参数(如“with Object :”建议)。
但是,您的方法-mySel:
会使用BOOL
参数。框架中的任何内容都不会自动将NSNumber
取消装箱,以将其转换为BOOL
。相反,您的方法正在接收对象指针值,但将其解释为BOOL
。
现在,BOOL
是unsigned char
,或者在某些体系结构上是bool
。因此,只有低位字节或低位由“if”语句检查。指向NSNumber
的指针很可能具有零低字节或位。请注意,NSNumber
对象的值是什么并不重要。只检查其地址。
调试器可能很混乱。它可能相当于“保持对象指针>的po<完整64位寄存器值”。因此,即使您的程序只检查低字节或位,调试器也会检查完整的64位值并将其视为对象指针。因此,调试器会误导你应该发生什么。
正如其他人所建议的那样,您可以将-mySel:
方法更改为NSNumber*
而不是BOOL
。您必须使用-boolValue
方法来检查该对象的值。
但是,您也可以使用Grand Central Dispatch(GCD)而不是-performSelectorInBackground:withObject:
来避免此类问题。您的代码可能是:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self mySel:YES];
});
无需将YES
值包装到对象中,因此在方法中对其进行错误解释没有任何问题。而且,如果您确实遇到了类型不匹配的情况,编译器可以识别它并向您发出警告,而-performSelector...
方法无法做到这一点。
或者,如果您真的不需要-mySel:
方法,除非您想通过选择器引用它,您可以直接将其代码内联到块中。
答案 2 :(得分:0)
BOOL
不是Objective-C中的对象。解决此错误的一种方法是通过BOOL
(对象)传递NSNumber
值(只是0或1)。
[self performSelectorInBackground:@selector(mySel:) withObject:[NSNumber numberWithBool:YES];
- (void)mySel:(id)suppressUserAlerts {
BOOL suppressUserAlertsBool = suppressUserAlerts.boolValue;
// ...
}
编辑:请注意,您仍可以传递@YES
而不是[NSNumber numberWithBool:YES]
,因为Cocoa会为您处理转化。我只是使用numberWithBool
来更明确。