在从文件中读取JSON数据的以下场景中,我有以下代码块:
// Fetch URL
let url = Bundle.main.url(forResource: "sampleJSON", withExtension: "json")!
// Load Data
let data = try! Data(contentsOf: url)
// Deserialize JSON
let json = try! JSONSerialization.jsonObject(with: data, options: [])
这段代码本身是否正确,或者将其包含在do-catch块中应该更好吗?我问的是因为我看到了使用URLSession从Web中提取数据的情况,开发人员在do-catch块中执行JSONSerialization。有没有理由在使用URLSession时这样做,而不是简单地从文件中提取JSON数据?对于这样的事情,最佳做法是什么?
答案 0 :(得分:4)
1 - 这段代码本身是否正确,或者将其包含在do-catch块中应该更好吗?
答:这段代码是正确的。如果你的sampleJSON.json
文件在你的和你的JSON文件中的数据被正确格式化 AND JSONSerialization
成功解析数据提供。
2 - 我问,因为我在使用URLSession从网络中提取数据时遇到了一些情况,开发人员在do-catch块中执行JSONSerialization。有没有理由在使用URLSession时这样做,而不是简单地从文件中提取JSON数据?对于这样的事情,最佳做法是什么?
答:在Web上使用数据(本例中为JSON)时会更频繁地看到do-catch语句,因为API可能因任何原因而中断(必须显示的数据规范错误,Web应用程序中的错误)本身等)如果发生这种情况,我们不希望我们的应用程序崩溃。
我说CRASH是因为您使用了!
而不会将错误传播到应用程序的上层,它会尝试强制执行操作,如果失败则会使应用程序崩溃。
此时您可能已经意识到,在使用捆绑包中的数据时,您没有看到do-catch语句的原因是因为应用程序开发人员自己提供了JSON,所以我假设您确定文件的内容,但我仍然使用do-catch语句,因为可能出现问题,并且不希望我的应用程序因为这样的愚蠢事情而崩溃。
我建议始终使用抛出/重新抛出甚至是?
的错误传播,这样您就可以测试零结果。
我已经编写了一个small article here,其中包含一些技巧以及它在Swift 2.1中是如何工作的,在Swift 3.1中没有太多变化,所以你可以用来研究do-catch语句。
我会改写你提供的代码:
警告:未经编辑的代码
enum JSONFromFileError: Error {
case fileNotInBundle(String)
case deserializationError
case getDataError(URL)
}
func json(from file: String) throws -> Any {
// Fetch URL in Bundle
guard let url = Bundle.main.url(forResource: file, withExtension: "json") else {
throw JSONFromFileError.fileNotInBundle(file)
}
// Load Data from url
guard let data = try? Data(contentsOf: url) else {
throw JSONFromFileError.getDataError(url)
}
// Deserialize JSON
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else {
throw JSONFromFileError.deserializationError
}
return json
}
do {
let myJsonObject = try json(from: "sampleJSON")
print(myJsonObject)
} catch let error {
print(error)
}
答案 1 :(得分:3)
对于throwable
的每个函数,通常应该使用try-catch块。使用当前代码,如果您的任何一个try块失败(数据无法从url下载或者它不是有效的json),强制trys将失败并导致运行时异常。
let url = Bundle.main.url(forResource: "sampleJSON", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: [])
} catch {
//handle error
}
如果你不关心函数会抛出的错误,你可以使用try?
,当函数抛出错误时返回nil
。这样你的代码就会崩溃。
guard let data = try? Data(contentsOf: url) else {return}
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else {return}
答案 2 :(得分:1)
Firstly
,建议将任何抛出的函数(使用try)包装到do-catch块中。在我看来,我还将执行一个do-catch块,以防我在不知情的情况下修改sampleJSON文件,这会导致JSON的格式受到干扰。
Secondly
,对代码中的never use force unwrap at all
来说绝对是一个好习惯。
Lastly
,我们应该始终捕获序列化异常并抛出调用者,最终将通知视图抛出错误对话框。