Understanding fixed error: Sending NSError *const __strong* to parameter

Understanding fixed error: Sending NSError *const __strong* to parameter

在写我原来的问题时,我无意中解决了我的问题。我想了解为什么我的更改会导致修复。

我写了一个 class 方法,它接受一个 NSString 和一个 NSError **。如果字符串在我的应用程序中是有效密码,方法 returns YES,如果不是,则方法 NO。如果返回 NO,则在方法内部设置通过引用传递的 NSError

验证方法如下:

@interface PasswordValidator

+ (BOOL)isValid:(NSString *)password error:(NSError **)error {

    NSError *err = nil;

    if (!password || password.length < 1) {
        err = [NSError errorWithDomain:...];
    }

    // Rest of logic omitted for brevity

    if (err) {
        if (error) {
            *error = err;
        }
        return NO;
    }

    return YES;
}
@end

在我的测试中,我错误地尝试检查 NSError 对象是否存在,如下所示:

    it(@"should set error if password is nil", ^{
        NSError *error;
        expect([PasswordValidator isValid:nil error:&error]).toNot.beNil();
    });

忽略测试包含逻辑错误的事实,代码导致编译器抱怨错误:Sending NSError *const __strong* to parameter of type 'NSError *__autoreleasing* changes retain/release properters of pointer

更新测试后,PasswordValidator:isValid:error 的调用发生在单独的行上,错误消失了:

    // The test below did not cause compilation issues.
    it(@"should return NO if password is nil", ^{
        NSError *error;
        [HAYPasswordValidator isValid:nil error:&error];
        expect(error).toNot.beNil();
    });

我的问题是,为什么编译器最初会抱怨?将方法调用分离到单独的行来解决问题的原因是什么?

一个 NSError** 参数实际上是一个 NSError __autoreleasing 参数。如果传递 &error,编译器将创建一个本地 NSError* __autoreleasing 变量,将其传递给方法,并将结果存储到错误中。这有点复杂,但大多数人从来没有注意到。

我怀疑 expect 宏或函数做了一些复杂的事情,使编译器变得复杂,并且它会抱怨。您可以检查预处理器输出以查看实际编译的内容。我不确定错误消息中的 "const" 是从哪里来的。

您使用的是什么测试工具?如果那个 expect() 函数实际上是一个将表达式包装在一个块中的宏,那么这可能会导致编译器以这种方式抱怨。

但是,你的固定测试是错误的.

您无法直接测试 nil/non-nil 的错误。如果方法 returns NO(或 nil,通常是任何指示错误的方法),error 将仅设置为定义的值。然后并且只有那时才会定义 error

考虑 isValid:error: 方法的实施。如果没有错误,则不会触及 error 参数。如果 error 在进入该方法时未初始化,它在成功案例中仍将未初始化,如果您只测试 error 本身,您的测试用例可能会在不应该失败的情况下失败。

如果您尝试在块中捕获 NSError ** 变量,您也可能会遇到此错误。捕获 __autoreleasing 个变量是不可能的朋友。所需要做的就是在块内重新声明 NSError **。