4

我正在关注 G. Lee 的 Test-Driven iOS development 一书,遇到了这个单元测试,我不明白。首先,如果您需要更多代码,请立即告诉我。

-(void)testDelegateNotifiedOfErrorWhenNewsBuilderFails
{
    MockNewsBuilder *builder = [MockNewsBuilder new];
    builder.arrayToReturn = nil;
    builder.errorToSet = underlyingError;
    newsManager.newsBuilder = builder;
    [newsManager receivedNewsJSON:@"Fake Json"];
    ...
}

-(void)receivedNewsJSON:(NSString *)objectNotation
{
    NSError *error = nil;
    //  As you see error is nil and I am passing in a nil error.
    NSArray *news = [_newsBuilder newsFromJSON:objectNotation error:&error];
    ...
}

@implementation MockNewsBuilder

-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error
{
    // But once I arrive here, error is no longer nil.
    // (NSError **) error = 0x00007fff5cb887f0 domain: @"Fake Json" - code: 0
    ...
}

错误是如何自动设置的?

更新:

感谢大家的积极讨论和建议。答案解释了调用方如何因为 & 得到错误实例,我明白这一点。我的问题仍然是为什么被调用方指向一个填充的 NSError 实例,即使它必须为零。我没有在其中设置错误实例,newsFromJSON:error:那么它是如何在那里填充的?

我刚改[newsManager receivedNewsJSON:@"Fake Json1"];了,里面的错误实例newsFromJSON:error:马上就反映了 (NSError **) error = 0x00007fff5b9b27f0 domain: @"Fake Json1" - code: 0。它非常混乱......

4

3 回答 3

3

这只是指向指针概念的指针。您正在将引用错误对象的引用 &error 传递给方法-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error;

这将在您传递的内存指针处更新错误对象。

看到这是指针指针的概念。

在此处输入图像描述

更新:

您的错误对象为零,是的,它是正确的。但是你不是将错误对象传递给方法,而是错误对象( )newsFromJSON的内存地址。&error那是错误对象的内存地址。
这就是为什么您在newsFromJSON方法中获得非空值的原因。

还有一件事,您可以newsFromJSON使用 operator( *operator) 的内容访问方法中的原始对象,例如**error = something;

这将更新您在调用方方法NSError *error中声明的原始对象 ( )。 在 C 或 CPP 或 Objective-C 中,& 是运算符的地址,* 是运算符的内容。

&obj -> 给出 obj 的内存地址
*obj -> 给出 obj 中内存地址的内容。

于 2014-12-18T10:02:52.693 回答
0

** 是指向指针的指针。这意味着您需要将指针地址传递给函数或方法。Objective-C 是 C 的严格超集。这意味着 C 中的函数和方法只能返回一个值。有两种方法。一种是将所有返回值包装在结构或 NSDictionaries 或其他集合中。这种方式称为 outParameter 它传递一个指针地址。C 是一种复制语言。但是指针是可移植的黑洞,它允许你在 C 中做些疯狂的事情。Objective-C 和 C++ 给你同样的疯狂。

该错误是由 Apple 的框架代码设置的。Cocoa 模式通常是返回一个 BOOL 并传入一个 NSError 指针地址。如果 BOOL 为 NO,请检查 NSError。Apple 框架会在你的 NSError 指针地址框中放一些礼物。

有时他们不使用 BOOL 而是返回一个对象或 nil。

Core Foundation C 框架的工作方式非常相似,并且大量使用输入和输出参数。

于 2014-12-18T10:12:12.080 回答
0

error是一个类型的变量NSError*,即“指向 NSError 的指针”(在 Objective-C 中,所有对象都作为引用处理,而不是例如 C++)。

这意味着这error是一个(本地)变量,它存储实际NSError对象的地址,最初是nil.

您调用的方法会创建一个(自动释放的)NSError实例。为了获得对该实例的引用,您需要将指针的地址或 传递给该方法,该地址&error又是“指向指针的指针NSError”类型(注意两级间接)。

您这样做是因为 C 中的函数和 Objective-C 中的方法的参数是按值传递的:如果您只是传递error,则存储在那里的值(nil)单独被复制,并且无论被调用的方法做什么,变量的内容erroron你这边(调用者)不能被修改。为此,您需要传递错误的地址,或&error.

这样,被调用的方法可以“更改” error(保存在那里的地址)的内容,使其指向新创建的NSError实例。

是否有意义?

附录:这是在 Cocoa 中经常看到的一种非常常见的模式:被调用的方法可能会失败,而不是仅仅使用返回值来表示成功/失败,并且传递了额外的 'in/out' 参数来检索详细的错误发生故障时的信息。失败时,该方法可以返回falseNO0等),但另外可以在实例内部提供更详细的错误报告(例如失败的原因)NSError

已编辑:正如@Droppy 所说,并且看到所有涉及的代码都是您自己的(即,不是某些第一方或第三方框架),除非您在某处明确分配,否则不可能将error其设置为其他任何内容。nil也许您应该在调试器中“观察”它以查看它的设置时间/位置。由于消息似乎设置为@"Fake JSON",因此您可以做的第一件事是在项目(所有文件)中搜索该字符串。

于 2014-12-18T10:10:51.197 回答