何时使用Swift使用do-catch块

时间:2017-06-28 16:39:06

标签: ios json swift do-catch

在从文件中读取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数据?对于这样的事情,最佳做法是什么?

3 个答案:

答案 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语句,因为可能出现问题,并且不希望我的应用程序因为这样的愚蠢事情而崩溃。

TL; DR

我建议始终使用抛出/重新抛出甚至是?的错误传播,这样您就可以测试零结果。

我已经编写了一个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,我们应该始终捕获序列化异常并抛出调用者,最终将通知视图抛出错误对话框。