了解修复错误:将NSError * const __strong *发送到参数

时间:2015-04-18 18:42:49

标签: objective-c memory-management compiler-errors

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

我写了一个接受NSStringNSError **的类方法。如果字符串在我的应用程序中是有效密码,则该方法返回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();
    });

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

3 个答案:

答案 0 :(得分:3)

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

然而您的固定测试错误

您无法直接测试nil / non-nil的错误。如果方法返回error(或NO,通常 - 表示错误,则nil将仅设置为已定义的值。然后,只有这样才能定义error

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

答案 1 :(得分:1)

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

我怀疑期望的宏或函数做了一些复杂的事情,这使得编译器变得复杂,并且它抱怨。您可以检查预处理器输出以查看实际编译的内容。我不确定错误消息中的“const”来自何处。

答案 2 :(得分:0)

您还可以遇到此错误,您尝试在块中捕获NSError **变量。捕获__autoreleasing变量是一个不能做的amigo。所需要的只是在块内重新声明NSError **。