没有将NSError设置为nil会导致崩溃

时间:2012-12-12 19:32:49

标签: objective-c ios

我遇到了一个非常奇怪的问题,经过几个月的测试后,我正准备提交应用程序。

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

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

在过去的几个月里,这种方法已经停止使用,绝对没有问题。但就在今天,它刚刚停止工作。它现在总是导致错误(没有描述;只是一个非nill错误)。

事实证明,解决问题所需要做的就是设置NSError *e = nil;。我认为做这件事只是一种好习惯,而不是绝对批评。这吓到我了。我想知道我在代码中做了多少次。任何人都可以解释可能发生的事情吗?

另外,我正在使用ARC,我想这会发生这种情况更加奇怪。

3 个答案:

答案 0 :(得分:4)

您的代码错误,您的修复也是如此。你需要做的是说

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

如果resultnil以外的任何内容,则您不允许 关于e的内容。


这里的基本原因是具有NSError**返回值的API不需要在该位置放置任何内容,除非API返回错误。通常这意味着在非错误的情况下,他们根本不会修改该值,因此您之前在e变量中所拥有的内容就是您所拥有的。如果您的代码是在没有ARC的情况下编译的,那么您的e变量将从堆栈中获取垃圾。在ARC下,它会被初始化为nil,但是我猜测你不会因为我将要去的ARC而被拒绝。

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

现在,我认为你的代码不是ARC的原因是因为据我所知,现在所有的Cocoa API都在努力而不是修改{{ 1}}值,除非发生错误。这符合一年或两年前建立的新指南(可能是在2011年或2012年初,我忘记了哪些),说具有NSError**参数的方法只应在错误中修改它案件。这是为了允许代码NSError**工作,即使它实际上没有遵循NSError *e = nil; [foo callAPIWithError:e]; if (e) ... API的规则,纯粹作为一个实际问题,在面对错误时更具弹性码。由于ARC使用对象类型清除所有自动变量,因此崩溃表明NSError未被填空,因此您不在ARC中。

然而,尽管我刚刚在上一段中说过,但您仍然不应该假设任何启用了e的API都会在没有引发错误时单独保留NSError值。目前实施此类API的准则确实应该是真的,但这并不是一项艰难的要求。在这些指南之前编写的任何代码都可能不会那样,并且在指南之后编写的任何代码都可能忽略它们。调用启用了NSError的API的规则继续声明必须查询API的返回值,并且只有在返回值指示发生错误时才可以观察到NSError变量。

答案 1 :(得分: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变量设置为nil(首选的是首选)。

答案 2 :(得分:0)

该方法的reference说:

  

返回值   数据中JSON数据的Foundation对象,如果发生错误,则为nil。

因此,请使用返回值来检测错误,并且只有在您需要详细信息时才会查看错误对象。