我遇到了一个非常奇怪的问题,经过几个月的测试后,我正要提交应用程序时恰好弹出。
我有以下方法,它接受一些 JSON 数据并将其转换为字典:
NSError *e;
NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers error:&e];
if (e != nil) return nil;
这几个月一直在不停地使用这个方法,完全没有问题。但就在今天,它刚刚停止工作。它现在总是导致错误(没有描述;只是一个非空错误)。
事实证明,我必须做的就是设置 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 callAPIWithError:e]; if (e) ...
的代码工作,即使这实际上并没有遵循 NSError
的规则API,纯粹作为一个实际问题,在面对不正确的代码时更具弹性。由于 ARC 消除了所有具有对象类型的自动变量,因此您的崩溃表明 e
没有消失,因此你不在 ARC 中。
然而,尽管我在上一段中刚刚说过,你仍然不应该假设任何 NSError
-enabled API 将保留 NSError
没有错误抛出时单独的值。当前实现此类 API 的指导方针确实说这应该是正确的,但这并不是硬性要求。在这些准则之前编写的任何代码可能不会那样做,而在这些准则之后编写的任何代码可能只是忽略它们。调用 NSError
的规则-enabled API 继续声明必须查询 API 的返回值,并且 NSError*
仅当返回值指示发生错误时才可观察到变量。
关于objective-c - 不将 NSError 设置为 nil 会导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13847207/