Objective-C && 不会为 !var 短路

Objective-C && doesn't short circuit for !var

尝试运行这个:

UIView *testView = nil;

NSLog(@"Take 1");
NSString *message = @"view doesn't exist";
if (!testView && !testView.subviews) {
   message = @"this message should never appear" ;
}
NSLog(message);


NSLog(@"Take 2");
message = @"view doesn't exist";
if (testView != nil && testView.subviews != nil) {
    message = @"this message should never appear" ;
}
NSLog(message);

NSLog(@"Take 3");
message = @"view doesn't exist";
if (!testView) {
    if (!testView.subviews) {
        message = @"this message should never appear" ;
    }
}
NSLog(message);

NSLog(@"Take 4");
message = @"view doesn't exist";
if (testView != nil) {
    if (testView.subviews != nil) {     
        message = @"this message should never appear" ;
    }
}
NSLog(message);

我得到的输出是:

Take 1
this message should never appear
Take 2
view doesn't exist
Take 3
this message should never appear
Take 4
view doesn't exist

为什么 !testView 的 Obj-C 没有短路(在 Take 1 中)?

Take 3中testView明明是nil,为什么会进入!testView

我不应该测试 nil 对象的功能吗(例如,当我测试 subviews 时)?

您看到的输出是正确的,短路行为也正常工作。

当计算布尔表达式时,如果表达式不为 0,则结​​果被认为是 true,如果表达式为 0,则结​​果被认为是 false。因此,在任何有 if (something) 的地方,您都可以将其读作 if (something != 0) . ! 运算符是否定运算符,因此如果展开它,第一种情况会得到以下结果:!(testView != 0) && !(testView.subviews != 0)。可以删除双重否定,得到 (testView == 0) && (testView.subviews == 0) 这显然是真的(nil 也是 0)。

那里也正确地应用了短路,你只是看不到它。为了证明您可以在测试中使用一些包装函数:

id testFunc( id value ) {
    NSLog(@"testFunc: %@", value );
    return value;
}

并在您的测试中使用它:if (!testFunc(testView) && !testFunc(testView.subviews))

简而言之,您对布尔非运算符 ! 的假设是错误的。它进入 if (!testView) 因为 testView 是 nil.

这里没有什么奇怪的事情发生。我重写了您的代码,将 testView 替换为 nil,将 testView.subviews 替换为 nil(发送至 nil return nil 的消息)。

NSLog(@"Take 1");
NSString *message = @"if clause was false";
if (!nil && !nil) { // if(true && true)
   message = @"if clause was true" ;
}
NSLog(message); // outputs "if clause was true"


NSLog(@"Take 2");
message = @"if clause was false";
if (nil != nil && nil != nil) { // if (false && false)
    message = @"if clause was true" ;
}
NSLog(message); // outputs "if clause was false"

NSLog(@"Take 3");
message = @"if clause was false";
if (!nil) { // if (true)
    if (!nil) { // if (true)
        message = @"if clause was true" ;
    }
}
NSLog(message); // outputs "if clause was true"

NSLog(@"Take 4");
message = @"if clause was false";
if (nil != nil) { // if (false)
    if (nil != nil) { // if (false)
        message = @"if clause was true" ;
    }
}
NSLog(message); // outputs "if clause was false"

如果你想知道视图是否存在,你可以使用类似的东西:

if (testView) {
    NSLog(@"View exists a.k.a. testView != nil");
} else {
    NSLog(@"View doesn't exist a.k.a. testView == nil");
}

我建议只使用 if (testView)if (!testView) 来检查对象是否存在。这是Objective-C社区的标准,读起来更清楚。