关于ios:NSError对象已在第一个方法调用中填充

NSError object already populated on first method call

我正在关注G. Lee撰写的《测试驱动的iOS开发》一书,遇到了我不理解的单元测试。 首先,如果您需要更多代码,请立即通知我。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-(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实例,即使它必须为nil。 我没有在newsFromJSON:error:中设置错误实例,所以它在那里已经被填充了吗?

我刚刚更改了[newsManager receivedNewsJSON:@"Fake Json1"];,而newsFromJSON:error:中的错误实例立即反映了出来
(NSError **) error = 0x00007fff5b9b27f0 domain: @"Fake Json1" - code: 0。 它非常令人困惑...


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

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

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

enter image description here

更新:

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

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

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

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


**是指向指针的指针。
这意味着您需要将指针地址传递给函数或方法。
Objective-C是C的严格超集。
这意味着在C语言中,函数和方法只能返回一个值。
有两种方法。
一种是将所有返回值包装在struct或NSDictionaries或其他集合中。
这种方式称为outParameter
它传入一个指针地址。
C是一种复制语言。 但是指针是可移植的黑洞,可让您在C语言中执行野性操作。
Objective-C和C ++具有相同的野性。

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

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

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


error是类型为NSError*的变量,它是" NSError的指针"(在Objective-C中,所有对象都作为引用来处理,而不是像C ++那样)。

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

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

这样做是因为按值传递C中函数的参数和Objective-C中的方法:如果仅传递了error,则仅复制存储在其中的值(nil),无论调用的方法做什么,您端(调用方)变量error的内容无法修改。为此,您需要传递错误地址或&error

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

是否有意义?

附录:这是可可中非常常见的一种非常常见的模式:被调用的方法可能会失败,并且不仅使用返回值来表示成功/失败,还传递了附加的"输入/输出"参数来检索详细错误发生故障时的信息。失败时,该方法可以返回false(NO0等),但除此之外可以在NSError实例内部提供更详细的错误报告(例如,失败原因)。

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