让我们从在 Objective-C 中运行一些等效的代码开始,以便我们了解 Cocoa 在这里做了什么:
NSDictionary* d = @{@"Howdy": [NSObject new]};
NSError* err;
[NSJSONSerialization dataWithJSONObject:d options:0 error:&err];
NSLog(@"%@", err);
如果这是导致 NSError 的事情,我们将能够读取 err 的值并将其打印到控制台。但事实并非如此,我们也不能。我们从未接触过 NSLog 语句。相反,程序会毫不客气地崩溃:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Invalid type in JSON write (NSObject)'
1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48
2 Foundation 0x00007fff2580cb68 -[_NSJSONWriter writeRootObject:toStream:options:error:] + 0
3 Foundation 0x00007fff2580ff03 ___writeJSONObject_block_invoke + 371
[and so on]
这不是一个NSError。这是一个 NSException。它们是完全不同的东西,基本上这意味着我们的程序崩溃了。这不是错误的抛出和捕获;是猝死。
这就是documentation 警告我们会发生的事情。如果我们提供一个无法转换为 JSON 的对象,则此方法 dataWithJSONObject:options:error 不会按顺序失败。它反而崩溃了:
如果obj 不会生成有效的 JSON,则会引发异常。此异常在解析之前被抛出,表示编程错误,而不是内部错误。 您应该在使用isValidJSONObject:调用此方法之前检查输入是否会生成有效的JSON。
(斜体是我的。)
因此,发现问题并防止崩溃的正确方法是致电isValidJSONObject:first。这个方法,dataWithJSONObject:options:error,不会捕捉到这种问题,只返回一个 NSError;它会杀死整个程序。
这就是发生在你身上的事。您对try JSONSerialization.data(withJSONObject:) 的呼叫没有 throw。它只是崩溃了。如果您在实际的 Swift 应用程序中自行尝试,您会看到:
override func viewDidLoad() {
super.viewDidLoad()
do {
try testCreateJSONFrominValidDictionaryThrows()
} catch {
print("oops")
}
}
func createBodyDataFrom(dictionary: [String: Any]) throws -> Data {
let bodyData = try JSONSerialization.data(withJSONObject: dictionary, options: [])
return bodyData
}
func testCreateJSONFrominValidDictionaryThrows() throws {
let validDictionary: [String: Any] = [
"object": NSObject()
]
try createBodyDataFrom(dictionary: validDictionary)
}
我们运行应用程序,会发生什么?我们不打印“oops”。相反,我们会遇到与 Objective-C 中完全相同的崩溃。
这也是你的案例所发生的事情。我们从不投掷,因为我们反而坠毁了。测试失败报告了这一事实。你的testClient 从你下面崩溃了(你可以通过一些控制台的旋转来检测到这一点),并且测试本身作为失败返回,因为我们从未抛出一个 NSError。
Cocoa 抛出 NSException 和返回 NSError 的区别在这里很重要。只有后者才算 Swift 抛出错误;前者是崩溃。参见示例
How can I throw an NSError from a Swift class and catch it in an Objective-C class?
Avoid handling all exceptions until they've reached a global handler
How to catch NSUnknownKeyException in swift 2.2?