我需要访问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")
}
}
错误在最后一行,“未解决的标识符”。
答案 0 :(得分:2)
在您不使用
if
语句之外的变量的意义上,它的行为类似于else
-if
语句吗?
是的。但是就像if
-else
语句一样,您可以在do
-catch
之前定义变量:
例如在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
答案 1 :(得分:1)
您的代码中有四个(!)非常糟糕的做法。
String(contentsOf
这样的API同步加载数据。使用URLSession
之类的异步API。catch
块中打印无意义的文字字符串。打印error
实例。在do - catch
块中,始终将所有 good 代码放在do
范围内。这样可以解决您的问题。
do {
let tecionexContent = try String(contentsOf: URL("https://www.hackingwithswift.com")!)
let tecGrid = tecionexContent.components(separatedBy: "\n")
} catch { print(error) }
推荐
URLSession.shared.dataTask(with: URL("https://www.hackingwithswift.com")!) { data, _ , error in
if let error = error { print(error); return }
let tecionexContent = String(data: data!, encoding: .utf8)!
let tecGrid = tecionexContent.components(separatedBy: "\n")
}.resume()
答案 2 :(得分:0)
代码的问题是,您正在块/闭包(这是局部作用域)中定义变量。您的变量应位于两个块都可以看到的范围内。这意味着在catch块中,变量不存在。具体来说,您尝试从实例化其闭合的闭包外部引用名为TECIONEXContent
的字符串变量。
关于某些常规样式要点:请坚持使用变量的快速命名约定(即驼峰式大小写),而类等应大写。 (出于在操场上运行以下代码的目的,我使用了任意函数名称,但您可以从生命周期方法中使用它。)
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
private var tecGrid: [String]? {
didSet {
// Update some UI Here (insuring your on the main thread)
print(self.tecGrid)
}
}
func test() {
do {
var texionicContent = try String(contentsOf:URL(string: "https://www.hackingwithswift.com")!)
tecGrid = texionicContent.components(separatedBy: "\n")
}
catch let error {
print("Catch the error")
}
}
}
let play = MyViewController(nibName: nil, bundle: nil)
play.test()