Objective c 不将NSError设置为nil会导致崩溃

Objective c 不将NSError设置为nil会导致崩溃,objective-c,ios,Objective C,Ios,我遇到了一个非常奇怪的问题,经过几个月的测试,在我准备提交应用程序的时候,这个问题碰巧出现了 我有一个folliwing方法,它获取一些JSON数据并将其转换为字典: NSError *e; NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:

我遇到了一个非常奇怪的问题,经过几个月的测试,在我准备提交应用程序的时候,这个问题碰巧出现了

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

NSError *e;
NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData 
                              options:NSJSONReadingMutableContainers error:&e];
if (e != nil) return nil;
在过去的几个月里,这种方法一直在使用,没有任何问题。但就在今天,它停止了工作。它现在总是导致错误(没有描述;只是一个非nill错误)

事实证明,我所要做的就是设置
NSError*e=nil。我认为这样做只是一种良好的做法,而不是绝对的批评。这让我害怕。我想知道在我的代码中还有多少次这样做。有人能解释一下可能发生的事情吗


另外,我使用的是ARC,我想这让发生这种情况更加奇怪。

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

if (result == nil) {
    // an error occurred, and the NSError* variable can now be consulted
}
如果
result
nil
之外的任何内容,则不允许对
e
的内容进行任何假设


这里的基本原因是,具有
NSError**
返回值的API不需要在该位置放置任何内容,除非API返回错误。通常,这意味着在无错误的情况下,它们根本不会修改值,因此无论您在
e
变量之前拥有什么,都是您在之后拥有的。如果编译代码时没有ARC,则
e
变量将包含堆栈中的垃圾。在ARC下,它将被初始化为
nil
,但我猜您不在ARC下,原因我会讲到

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

现在,我认为您的代码不是ARC的原因是,据我所知,目前所有Cocoa API都尽力不修改
NSError**
值,除非发生错误。这与一两年前制定的新指导方针(我忘记是2011年初还是2012年初制定的)一致,即具有
NSError**
参数的方法只能在错误情况下修改它。这是为了允许代码显示
NSError*e=nil;[foo callapirror:e];如果(e).
能够工作,即使这实际上没有遵循
NSError
API的规则,但纯粹是为了在面对错误代码时更具弹性。由于ARC将对象类型的所有自动变量置零,因此崩溃表明
e
未置零,因此您不在ARC中


但是,尽管我在上面的段落中已经说过,但是您仍然不应该假设任何启用了
NSError
的API在没有抛出错误时会保留
NSError
值。目前实施此类API的指导方针确实说这应该是正确的,但这不是一个硬性要求。在这些准则之前编写的任何代码都可能不会以这种方式运行,在这些准则之后编写的任何代码都可能忽略它们。调用启用了
NSError
的API的规则继续声明必须参考API的返回值,并且只有在返回值指示发生错误时才能遵守
NSError*
变量。

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

if (result == nil) {
    // an error occurred, and the NSError* variable can now be consulted
}
如果
result
nil
之外的任何内容,则不允许对
e
的内容进行任何假设


这里的基本原因是,具有
NSError**
返回值的API不需要在该位置放置任何内容,除非API返回错误。通常,这意味着在无错误的情况下,它们根本不会修改值,因此无论您在
e
变量之前拥有什么,都是您在之后拥有的。如果编译代码时没有ARC,则
e
变量将包含堆栈中的垃圾。在ARC下,它将被初始化为
nil
,但我猜您不在ARC下,原因我会讲到

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

现在,我认为您的代码不是ARC的原因是,据我所知,目前所有Cocoa API都尽力不修改
NSError**
值,除非发生错误。这与一两年前制定的新指导方针(我忘记是2011年初还是2012年初制定的)一致,即具有
NSError**
参数的方法只能在错误情况下修改它。这是为了允许代码显示
NSError*e=nil;[foo callapirror:e];如果(e).
能够工作,即使这实际上没有遵循
NSError
API的规则,但纯粹是为了在面对错误代码时更具弹性。由于ARC将对象类型的所有自动变量置零,因此崩溃表明
e
未置零,因此您不在ARC中

然而,尽管我在上面一段中已经说过,您仍然不应该假设任何
NSError
启用了API