如何在 SWIFT 5 中更改对象结构的值
How to change value of a Object Struct in SWIFT 5
我正在尝试从 JSON 类型中获取值,将它带到我的 var cryptos。但没有任何变化,var cryptos 仍然为零。甚至 Update void 中的密码值也发生了变化。我已经为这个问题苦苦挣扎了好几个小时。感谢您的回答。
这是我的代码:
var cryptos: Crypto? = nil
override func viewDidLoad() {
super.viewDidLoad()
update()
//I can't print this. ERROR: Unexpectedly found nil while unwrapping an Optional value
//print(self.cryptos!.data[0].name)
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
@objc func update() {
if let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest") {
var request = URLRequest(url: url)
request.addValue("305782b4-...-1835adfe147a", forHTTPHeaderField: "X-CMC_PRO_API_KEY")
request.httpMethod = "GET"
let dataTask = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
do {
do {
let response = try JSONDecoder().decode(Crypto.self, from: data!)
self.cryptos = response
//but here I can. Why??
print(self.cryptos!.data[0].name)
} catch { print(error) }
}
}
dataTask.resume()
}
}
这是我的结构:
public struct Crypto : Codable {
struct data : Codable {
let id: Int
let name: String
let symbol: String
let cmc_rank: Int
let slug: String
struct quote : Codable {
struct USD : Codable {
let price: Double
let volume_24h: Double
let percent_change_1h: Double
let percent_change_24h: Double
let percent_change_7d: Double
}
let USD: USD
}
let quote: quote
}
let data: [data]
}
向函数添加一个完成块,因为它是一个异步任务。
override func viewDidLoad() {
super.viewDidLoad()
update {
print(self.cryptos?.data[0].name ?? "")
}
//...
}
@objc func update(completion: @escaping () -> Void) {
if let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest") {
//...
let dataTask = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
do {
let response = try JSONDecoder().decode(Crypto.self, from: data!)
self.cryptos = response
print(self.cryptos!.data[0].name)
completion()
} catch {
print(error)
completion()
}
}
dataTask.resume()
}
}
update
异步运行。所以为它提供一个完成处理程序:
几点建议:
我会定义一个响应对象来包装负载。 data
键不是您需要在模型对象中永久保留的东西:
public struct ResponseObject<T: Codable>: Codable {
let data: [T]
}
struct Crypto: Codable {
let id: Int
let name: String
let symbol: String
let cmc_rank: Int
let slug: String
struct Quote : Codable {
struct USD : Codable {
let price: Double
let volume_24h: Double
let percent_change_1h: Double
let percent_change_24h: Double
let percent_change_7d: Double
}
let USD: USD
}
let quote: Quote
}
我倾向于使用上面的通用模式,因此您可以在别处重用这个 ResponseObject
模式。
我会给 update
一个使用 Result
类型的完成处理程序:
@discardableResult
func update(completion: @escaping (Result<[Crypto], Error>) -> Void) -> URLSessionTask {
let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest")!
var request = URLRequest(url: url)
request.addValue("305782b4-...-1835adfe147a", forHTTPHeaderField: "X-CMC_PRO_API_KEY")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let responseData = data, error == nil else {
DispatchQueue.main.async { completion(.failure(error ?? NetworkError.unknownError(data, response))) }
return
}
do {
let response = try JSONDecoder().decode(ResponseObject<Crypto>.self, from: responseData)
DispatchQueue.main.async { completion(.success(response.data)) }
} catch {
DispatchQueue.main.async { completion(.failure(error)) }
}
}
task.resume()
return task
}
在哪里
enum NetworkError: Error {
case unknownError(Data?, URLResponse?)
}
仅供参考,除了完成处理程序闭包外,我还删除了强制展开运算符 (!
)。
我还会将此 return 设为 URLSessionTask
(以防来电者在将来的某个日期希望能够出于任何原因取消请求)。通过使其成为 @discardableResult
,这意味着您不需要调用者对 returned 值执行任何操作,但您为将来打开了大门。
然后 viewDidLoad
可以使用它来根据需要重新加载 table:
var cryptos: [Crypto] = []
override func viewDidLoad() {
super.viewDidLoad()
update() { result in
switch result {
case .failure(let error):
print(error)
case .success(let cryptos):
self.cryptos = cryptos
self.tableView.reloadData()
}
}
}
请注意,模型对象的更新和 table 的重新加载都在这个已被分派到主队列的完成处理程序中完成。所有 UI 和模型更新都应在主线程上进行。
我正在尝试从 JSON 类型中获取值,将它带到我的 var cryptos。但没有任何变化,var cryptos 仍然为零。甚至 Update void 中的密码值也发生了变化。我已经为这个问题苦苦挣扎了好几个小时。感谢您的回答。 这是我的代码:
var cryptos: Crypto? = nil
override func viewDidLoad() {
super.viewDidLoad()
update()
//I can't print this. ERROR: Unexpectedly found nil while unwrapping an Optional value
//print(self.cryptos!.data[0].name)
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
@objc func update() {
if let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest") {
var request = URLRequest(url: url)
request.addValue("305782b4-...-1835adfe147a", forHTTPHeaderField: "X-CMC_PRO_API_KEY")
request.httpMethod = "GET"
let dataTask = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
do {
do {
let response = try JSONDecoder().decode(Crypto.self, from: data!)
self.cryptos = response
//but here I can. Why??
print(self.cryptos!.data[0].name)
} catch { print(error) }
}
}
dataTask.resume()
}
}
这是我的结构:
public struct Crypto : Codable {
struct data : Codable {
let id: Int
let name: String
let symbol: String
let cmc_rank: Int
let slug: String
struct quote : Codable {
struct USD : Codable {
let price: Double
let volume_24h: Double
let percent_change_1h: Double
let percent_change_24h: Double
let percent_change_7d: Double
}
let USD: USD
}
let quote: quote
}
let data: [data]
}
向函数添加一个完成块,因为它是一个异步任务。
override func viewDidLoad() {
super.viewDidLoad()
update {
print(self.cryptos?.data[0].name ?? "")
}
//...
}
@objc func update(completion: @escaping () -> Void) {
if let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest") {
//...
let dataTask = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
do {
let response = try JSONDecoder().decode(Crypto.self, from: data!)
self.cryptos = response
print(self.cryptos!.data[0].name)
completion()
} catch {
print(error)
completion()
}
}
dataTask.resume()
}
}
update
异步运行。所以为它提供一个完成处理程序:
几点建议:
我会定义一个响应对象来包装负载。
data
键不是您需要在模型对象中永久保留的东西:public struct ResponseObject<T: Codable>: Codable { let data: [T] } struct Crypto: Codable { let id: Int let name: String let symbol: String let cmc_rank: Int let slug: String struct Quote : Codable { struct USD : Codable { let price: Double let volume_24h: Double let percent_change_1h: Double let percent_change_24h: Double let percent_change_7d: Double } let USD: USD } let quote: Quote }
我倾向于使用上面的通用模式,因此您可以在别处重用这个
ResponseObject
模式。我会给
update
一个使用Result
类型的完成处理程序:@discardableResult func update(completion: @escaping (Result<[Crypto], Error>) -> Void) -> URLSessionTask { let url = URL(string:"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest")! var request = URLRequest(url: url) request.addValue("305782b4-...-1835adfe147a", forHTTPHeaderField: "X-CMC_PRO_API_KEY") let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let responseData = data, error == nil else { DispatchQueue.main.async { completion(.failure(error ?? NetworkError.unknownError(data, response))) } return } do { let response = try JSONDecoder().decode(ResponseObject<Crypto>.self, from: responseData) DispatchQueue.main.async { completion(.success(response.data)) } } catch { DispatchQueue.main.async { completion(.failure(error)) } } } task.resume() return task }
在哪里
enum NetworkError: Error { case unknownError(Data?, URLResponse?) }
仅供参考,除了完成处理程序闭包外,我还删除了强制展开运算符 (
!
)。我还会将此 return 设为
URLSessionTask
(以防来电者在将来的某个日期希望能够出于任何原因取消请求)。通过使其成为@discardableResult
,这意味着您不需要调用者对 returned 值执行任何操作,但您为将来打开了大门。然后
viewDidLoad
可以使用它来根据需要重新加载 table:var cryptos: [Crypto] = [] override func viewDidLoad() { super.viewDidLoad() update() { result in switch result { case .failure(let error): print(error) case .success(let cryptos): self.cryptos = cryptos self.tableView.reloadData() } } }
请注意,模型对象的更新和 table 的重新加载都在这个已被分派到主队列的完成处理程序中完成。所有 UI 和模型更新都应在主线程上进行。