NSError对象已在第一次方法调用时填充

时间:2014-12-18 09:58:20

标签: ios objective-c nserror pointer-to-pointer

我正在关注G. Lee的“测试驱动的iOS开发”这本书,并且遇到了这个单元测试,我不明白。首先,如果您需要更多代码,请立即告诉我。

-(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。它非常令人困惑......

3 个答案:

答案 0 :(得分:3)

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

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

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

enter image description here

更新:

您的错误对象是nil,是的,它是正确的。但是您没有将该错误对象传递给newsFromJSON方法,而是传递错误对象的内存地址(&error)。这是错误对象的内存地址 这就是您在newsFromJSON方法中获得非空值的原因。

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

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

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

答案 1 :(得分:0)

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

<击>

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

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

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

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

有意义吗?

ADDENDUM:这是Cocoa中常见的一种非常常见的模式:被调用的方法可能会失败,而不仅仅是使用返回值来表示成功/ failure,并传递额外的“输入/输出”参数以在发生故障时检索详细的错误信息。失败时,该方法可以返回NO0NSError等),但另外还可以在{{}}内提供更详细的错误报告(例如失败原因) {1}}实例。

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

答案 2 :(得分:0)

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

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

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

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