我正在关注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。 它非常令人困惑...
-
这个stackoverflow.com/a/833124/790842回答了您的问题。
-
除非这不是第一次调用newsFromJSON或事先调用其他东西,否则没有理由为什么NSError已经被填充。 在显示的代码中,它应该为nil。
-
@Droppy感谢您主持讨论。 :)我已经更新了更多细节的问题。 但这对我来说仍然是个谜。
-
好的,在我看来,调试器向您显示了堆栈(它可能认为objectNotation参数是NSError的domain成员)。 尝试将调试器控制台与p *error等命令一起使用。
-
您知道"事物"与指向"事物"的指针之间的区别吗?
-
@HotLicks您要向谁讲话?
-
@HotLicks是的,我理解这一点,但这无助于解决问题。 这里的问题应该很清楚,不确定为什么要投票否决这个问题。
这只是指针概念的指针。您正在将对引用错误对象&error的引用传递给方法-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error;
这将更新您传递的内存指针处的错误对象。
看到这就是指针指向指针的概念。
更新:
您的错误对象为nil,是的。但是,您不是将错误对象传递给newsFromJSON方法,而是将错误对象的内存地址(&error)传递给。那是错误对象的内存地址。
这就是为什么您在newsFromJSON方法中在那里获得非null值的原因。
还有一件事,您可以使用operator(* operator)的内容访问newsFromJSON方法中的原始对象。
像**error = something;
这将更新您在调用方方法中声明的原始对象(NSError *error)。
在C或CPP或Objective-C中,&是运算符的地址,*是运算符的内容。
&obj->给出obj的内存地址
* obj->给出obj中内存地址的内容。
-
我不认为OP正在询问**的含义(尽管标题)。他想知道NSError是如何填充的。
-
NSError被填充在被调用端,因为您传递了指针的地址(双间接)。
-
@NicolasMiari因此,请解释为什么NSError对象似乎已被填充。
-
@Droppy阅读我的答案以及@uchuugaka的答案。之所以填充它,是因为您要传递变量error(即&error)的地址,以便被调用的方法可以"填充"它(通过分配新的NSError实例并将其分配给取消引用的指针,指针*(&error)。这是C。
-
@NicolasMiari那没有回答我的问题。 NSError对象本身似乎已填充(我知道已填充NSError对象的指针),但是为什么NSError域显示@"Fake Json"?
-
您是说要初始化NSError对象的属性?好吧,我想这是因为创建NSError实例的一侧(接受NSError**参数的方法)也方便地用适当的信息(例如错误消息)填充了它。重点在于:此NSError实例是由方法创建的,目的是报告在执行该方法期间发生的一些错误。如果该方法成功,则不会创建该实例,并且error保持为nil。这是可可粉中非常常见的模式(再次参见@uchuugakas答案)。
-
但这不是OPs代码所显示的。他将指针传递给nil NSError对象,这使我感到困惑。我认为他还了解指针到指针的工作原理,并用于将对象传递回调用者,但不理解为什么由于他的代码没有做到这一点(或者至少他所显示的部分)而似乎填充了它。
-
好吧,我的回答和另一个问题恰好解决了这个问题:创建了NSError实例并将其(方便地)填充到所调用的方法中。这是可可粉中常见的模式。
-
不;这两个答案都说明了如何以及为什么使用指针到指针,但没有说明为什么填充了(或看起来是)NSError对象。它甚至可能是lldb错误/功能。
-
我明白你的意思了:被调用的方法是他自己的代码(不是某些Apple框架),并且不分配NSError。你是这个意思吗?如果那是他的意思,并且正在发生,那一定是一个错误。可能ARC在做一些不请自来的事情吗?
-
我已确定答案。很抱歉长时间讨论。
**是指向指针的指针。
这意味着您需要将指针地址传递给函数或方法。
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框架的工作原理非常相似,并且大量使用输入和输出参数。
-
为什么NSObject似乎已填充(请参见@"Fake Json"的domain值)?
-
如果返回值是非nil或非NO,则永远不要关心或检查NSError。 (取决于所记录的方法)NSError不会给出有价值的含义,除非您的方法返回指示您应该检查错误。
-
这是一个可可约定,如果获得预期的回报,则应将NSError视为无意义。在底层,框架可能会将错误值保存在内存中的熟悉位置,以进行优化和/或框架调试。
-
听起来你不知道为什么。
-
哈哈。如我所说。照原样。为什么里面会有东西?不知道不需要。我知道您不应该关心其中的内容,除非API文档说有条件去关心其中的内容。
-
这个给你。 developer.apple.com/library/mac/documentation/Cocoa/Conceptual/
-
我熟悉通过指针到指针传回对象的概念,就像OP一样,但是OP(和我)想知道为什么未初始化的错误对象似乎会被填充。您似乎并没有意识到这一点,而是继续进行有关指针到指针和可可概念的讲座,而这并不是问题所在。
-
关键是除非您返回零或否,否则您不应该关心那里的内容。 什么或为什么都没有关系。 多数民众赞成在唯一的API合同。
-
让我们继续聊天中的讨论。
error是类型为NSError*的变量,它是" NSError的指针"(在Objective-C中,所有对象都作为引用来处理,而不是像C ++那样)。
这意味着error是一个(本地)变量,用于存储实际NSError对象(最初是nil)的地址。
您调用的方法将创建一个(自动释放的)NSError实例。为了获得对该实例的引用,您需要向该方法传递指针或&error的地址,该指针的类型又是"指向NSError的指针"(注意两个-级别间接)。
这样做是因为按值传递C中函数的参数和Objective-C中的方法:如果仅传递了error,则仅复制存储在其中的值(nil),无论调用的方法做什么,您端(调用方)变量error的内容无法修改。为此,您需要传递错误地址或&error。
这样,被调用的方法可以"更改" error的内容(此处保存的地址),使其指向新创建的NSError实例。
是否有意义?
附录:这是可可中非常常见的一种非常常见的模式:被调用的方法可能会失败,并且不仅使用返回值来表示成功/失败,还传递了附加的"输入/输出"参数来检索详细错误发生故障时的信息。失败时,该方法可以返回false(NO,0等),但除此之外可以在NSError实例内部提供更详细的错误报告(例如,失败原因)。 strike>
编辑:正如@Droppy所说,并看到所有涉及的代码都是您自己的(即,不是某些第一方或第三方框架),除非您明确将error设置为nil,否则不可能将error设置为除nil以外的任何其他值。 。也许您应该在调试器中"监视"它,以查看何时/何处对其进行设置。由于该消息似乎设置为@"Fake JSON",因此您可以做的第一件事是在项目(所有文件)中搜索该字符串。