2012-12-12 53 views
0

我遇到了一个非常奇怪的问题,经过几个月的测试刚刚发生,因为我正要提交应用程序。不设置NSError为零产生崩溃

我有folliwing方法,它需要一些JSON数据并将其转换为一个字典:

NSError *e; 
NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData 
           options:NSJSONReadingMutableContainers error:&e]; 
if (e != nil) return nil; 

在过去的几个月中,这种方法已被用来不停,绝对没有问题。但直到今天,它才停止工作。它现在总是导致错误(没有描述;只是一个非nill错误)。

事实证明,我所要解决的问题都是设置为NSError *e = nil;。我认为这只是一个很好的做法,并非绝对重要。这让我害怕。我想知道我在代码中做了多少次。任何人都可以解释可能会发生什么?

此外,我正在使用ARC,我猜这使得更奇怪的是,这种情况正在发生。

+0

e是一个局部变量,它在创建时不会自动初始化。它可能是碰巧为零,并且在你的应用程序发展后,它得到了一些不同的随机值。在e是财产而不是本地变量的情况下,如果没有你做任何事情,它应该是无效的。之后,调用JSONObjectWithData并且没有发生错误,e完全不被触及,并保留其初始“值”。这是基本的。 –

回答

4

您的代码有误,您的修复程序也是如此。什么,你需要做的是说

if (result == nil) { 
    // an error occurred, and the NSError* variable can now be consulted 
} 

如果result是除了nil什么,那么你就不能承担任何关于e内容。


这里的基本原因是,有NSError**返回值并不需要的API把任何东西在那个地方,除非该API返回一个错误。通常,这意味着在非错误的情况下,它们根本不会修改该值,所以无论您在之前的变量中如何,都是您以后所做的。如果你的代码是在没有ARC的情况下编译的,你的e变量将在其中有堆栈垃圾。在ARC下,它将被初始化为nil,但我猜你不在ARC下,原因是我会。

但是,它比这更复杂。即使该方法没有返回错误,它仍可能仍然修改了值NSError**。简单的例子是,如果此方法调用另一个方法,则将相同的NSError**传入该方法,然后从错误中恢复并返回成功值。然而,第二种方法可能已经填充了您的NSError*变量,其错误不再有效。

现在,为什么我觉得你的代码是不是ARC是因为,在我所知的原因,所有的可可原料药,这些天下功夫修改NSError**值,除非发生了错误。这符合一年或两年前制定的新准则(不论是在2011年初还是在2012年,我忘记了这一点),它们表示具有NSError**参数的方法只应在错误情况下对其进行修改。这是为了允许代码说NSError *e = nil; [foo callAPIWithError:e]; if (e) ...工作,即使这实际上并不遵循NSError API的规则,纯粹是作为实际问题在面对不正确的代码时更具弹性。由于ARC使用对象类型将所有自动变量删除,所以您的崩溃建议e未被删除,因此您不在ARC中。

但是,尽管我刚刚在上面的段落中提到过,但仍然不应该假定任何启用NSError的API都会在没有错误发生时单独保留NSError值。目前实施这些API的指导方针确实说这应该是真实的,但这不是一个硬性要求。在这些准则之前编写的任何代码都可能不会这样,并且在准则之后编写的任何代码可能会忽略它们。调用启用NSError的API的规则继续声明必须查阅API的返回值,并且只有在返回值指示发生错误时才可以观察NSError*变量。

+0

感谢您的详细解答。奇怪的是,我使用ARC虽然。奇怪的是,这种方法以前从未提出过任何问题,直到今天才开始,我今天唯一改变的是添加HockeyApp(beta测试/崩溃报告),但我不确定这会如何影响此方法。 – Snowman

+0

@mohabitar:这很好奇。我不知道编译器是否正在做任何形式的分析,并且认为,由于'NSError *'的第一次使用是在'NSError * __autoreleasing *'类型的外部参数中,因此变量本身应该是type '__autoreleasing'而不是'__strong',这消除了最初的'nil'赋值。这令我感到惊讶,但它在理论上是可能的。 –

0

reference该方法说:

Return Value A Foundation object from the JSON data in data, or nil if an error occurs.

所以使用返回值来检测错误,并且仅当您想详细看看错误对象。

2

让我解释一步一步错误的原因:

NSError *e; //some garbage non-nil value may be here 

NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData 
           options:NSJSONReadingMutableContainers error:&e]; // no error, e is untouched, garbage is still here 

if (e != nil) return nil; // there was no error but because of garbage we think there was one 

所以首先你需要检查结果值或集合E变量零(第一个是首选)。

+1

这是不正确的。在安全地检查错误之前,你必须首先检查'result'是否为'nil'。你也只是重复被问到的原始代码。 – rmaddy

+0

@rmaddy我没有告诉这是一个正确的方法。我只是逐步解释错误的原因。 – Max

+0

对不起,这不是很清楚。您发布了代码。这使它看起来像它应该是正确的代码。 – rmaddy

相关问题