首页 > 解决方案 > 在 catch 中引用 do 块中的变量

问题描述

我需要访问do语句中的变量。它的行为是否类似于if-else语句,因为您不使用if语句之外的变量?

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
    override func loadView() {

        do {
            //let url = URL?("https://www.hackingwithswift.com")
            let TECIONEXContent = try String(contentsOf: URL("https://www.hackingwithswift.com"))

        } catch { print("error")}

            //I need to access TECIONEXContent variable outside the do statement

            // Error: Use of unresolved identifier 'TECIONEXContent'
            var TECGrid = TECIONEXContent.components(separatedBy: "\n")
    }
}

错误在最后一行,“未解析的标识符”。

标签: swifttry-catch

解决方案


它的行为是否类似于if-else语句,因为您不使用if语句之外的变量?

是的。但就像if-语句一样,您可以在-else之前定义变量:docatch

例如在if-else语句中:

let foo: String

if bar > 1 {
    foo = "bigger than one"
} else {
    foo = "one or smaller"
}

或者,在您的情况下:

let url = URL(string: "https://www.hackingwithswift.com")!

let contents: String

do {
    contents = try String(contentsOf: url)
} catch { 
    print(error)
    return
}

let grid = contents.components(separatedBy: "\n")

或者,您实际上并没有对错误消息做任何事情,您可以完全消除do- catch

guard let contents = try? String(contentsOf: url) else {
    print("error")
    return
}

let grid = contents.components(separatedBy: "\n")

坦率地说,所有这些都说String(contentsOf:)了,无论如何,使用可能不是最好的模式,因为它执行同步网络请求,如果主线程被阻塞,这可能会让操作系统“看门狗”进程毫不客气地杀死你的应用程序;即使没有发生这种情况,在网络请求正在进行时冻结应用程序也不是一个好的用户体验。通常我们会使用URLSession

let url = URL(string: "https://www.hackingwithswift.com")!

URLSession.shared.dataTask(with: url) { data, response, error in
    guard
        let data = data,
        let httpResponse = response as? HTTPURLResponse,
        let string = String(data: data, encoding: .utf8) else {
            print(error ?? "Unknown error")
            return
    }

    guard 200 ..< 300 ~= httpResponse.statusCode else {
        print("Expected 2xx response, but got \(httpResponse.statusCode)")
        return
    }

    let grid = string.components(separatedBy: "\n")

    DispatchQueue.main.async {
        // use `grid` here
    }
}.resume()

无关,但是:

  • 惯例是以小写字母开头的变量名。

  • 你实施了loadView. 我们很少这样做,而是实施viewDidLoad,确保也调用super.viewDidLoad()

  • 如果你在操场上这样做,你显然也会设置needsIndefiniteExecution,如果你还没有。

因此:

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        performRequest()
    }

    func performRequest() {
        let url = URL(string: "https://www.hackingwithswift.com")!

        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let data = data,
                let httpResponse = response as? HTTPURLResponse,
                let string = String(data: data, encoding: .utf8) else {
                    print(error ?? "Unknown error")
                    return
            }

            guard 200 ..< 300 ~= httpResponse.statusCode else {
                print("Expected 2xx response, but got \(httpResponse.statusCode)")
                return
            }

            let grid = string.components(separatedBy: "\n")

            DispatchQueue.main.async {
                print(grid)
                // use `grid` here
            }
        }.resume()
    }
}

PlaygroundPage.current.liveView = ViewController()
PlaygroundPage.current.needsIndefiniteExecution = true

推荐阅读