我需要澄清一些关于将值传递出来的说明。我认为问题是使用dispatchQueue.main但我无法理解在哪里以及为什么
这是代码:
import UIKit
class ViewController: UIViewController {
var allCard = [Card]()
let card = Card(name: "", cost: 0, attack: 0, durability: 0, cardClass: "", cardSet: "", imageURL: "", goldenImageURL: "", type: "", mechanics: [["":""]], howToGetGolden: "")
override func viewDidLoad() {
super.viewDidLoad()
getCards()
print(allCard.count)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getCards() {
let url = URL(string: "https://omgvamp-hearthstone-v1.p.mashape.com/cards/sets/Classic?mashape-key=....")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil { // if urlSession have issues manage the error here
print(error)
} else { // if we have data, response, error then continue here
if let urlContent = data { // if data exist then
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [Dictionary<String, AnyObject>]
for cards in 0...jsonResult.count - 1 {
if let name = jsonResult[cards]["name"] as? String { //NAME Optionaml Bindings
self.card.name = name
} else {
self.card.name = ""
} // END Name Optionaml Bindings
if let cost = jsonResult[cards]["cost"] as? Int { //COST Optionaml Bindings
self.card.cost = cost
} else {
self.card.cost = 0
} // END COST Optionaml Bindings
if let attack = jsonResult[cards]["attack"] as? Int { //ATTACK Optionaml Bindings
self.card.attack = attack
} else {
self.card.attack = 0
} // END TTACK Optionaml Bindings
} catch { //catch error while parsing json
print("error")
}
}
} // end if/ELSE
} // end of task (closure)
task.resume()
}
}
我应该如何在这里使用dispatchQueue.main?它是异步还是同步?我试图在互联网上查看,但我找不到我理解的答案/:
感谢您的帮助
答案 0 :(得分:2)
您的下载需要时间,因此您必须等待它完成才能打印结果。为此,请向getCards()
添加完成处理程序:
func getCards(completion: () -> Void) {
// ... your code
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
// ... your code
for resultDict in jsonResult {
// create a new card ...
let card = Card(name: resultDict["name"], cost: resultDict["cost"], attack: resultDict["attack"], durability: 0, cardClass: "", cardSet: "", imageURL: "", goldenImageURL: "", type: "", mechanics: [["":""]], howToGetGolden: "")
// ... and actually add it to your array
allCard.append(card)
}
completion() // call completion after parsing
} // end of task (closure)
task.resume()
}
并将其称为:
override func viewDidLoad() {
super.viewDidLoad()
getCards() {
// the code in this closure is called after the download finished
print(allCard.count)
}
}
更新
URLSession
dataTask
在后台队列上调用它的完成处理程序。因此,如果您必须执行UI内容(必须在主队列上处理),您必须在主队列上调度完成处理程序:
替换:
completion() // call completion after parsing
使用:
DispatchQueue.main.async() {
completion() // call completion after parsing
}
答案 1 :(得分:2)
为您更正了代码。更好的方法是将你的牌移动到func并使其返回牌或如果失败通过关闭则为零。而且你也不需要在&#34;其他&#34; s中设置空字符串和0,因为你的卡已经用这些&#34;默认&#34;值。此外,您现在还有两个阵列 - 一个是func中的本地阵列,最近才下载了卡片。第二类实例变量将保存所有下载过的卡片。
转义意味着你的闭包可以在func返回后执行(在这种情况下,当请求完成时)。
[弱自我] - 我添加了它,因为你的视图控制器可能在请求完成时不存在,所以关闭不会将它保留在堆中并让它继续(例如当你厌倦等待响应时服务器,只需单击或取消并取消此视图控制器。)
我也在主线程上执行完成,因此您可以在闭包中更新UI。
class ViewController: UIViewController {
var allCards = [Card]()
override func viewDidLoad() {
super.viewDidLoad()
getCards() { [weak self] cards in
if cards != nil, self != nil {
self!.allCards.append(contentsOf: cards!)
print("Downloaded cards on this session \(cards!.count)")
print("All downloaded cards \(self!.allCards.count)")
// you can update UI here
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getCards(completion: @escaping ([Card]?)->Void) {
let url = URL(string: "https://omgvamp-hearthstone-v1.p.mashape.com/cards/sets/Classic?mashape-key=....")!
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
var cards: [Card]? = nil
if error != nil { // if urlSession have issues manage the error here
print(error ?? "")
} else { // if we have data, response, error then continue here
if let urlContent = data {
cards = [Card]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [Dictionary<String, AnyObject>]
for cards in 0...jsonResult.count - 1 {
let card = Card(name: "", cost: 0, attack: 0, durability: 0, cardClass: "", cardSet: "", imageURL: "", goldenImageURL: "", type: "", mechanics: [["":""]], howToGetGolden: "")
if let name = jsonResult[cards]["name"] as? String { //NAME Optionaml Bindings
card.name = name
} // END Name Optionaml Bindings
if let cost = jsonResult[cards]["cost"] as? Int { //COST Optionaml Bindings
card.cost = cost
} // END COST Optionaml Bindings
if let attack = jsonResult[cards]["attack"] as? Int { //ATTACK Optionaml Bindings
card.attack = attack
}
cards.append(card)
}
DispatchQueue.main.async { completion(cards) }
} catch { //catch error while parsing json
print("error")
}
}
}
if cards == nil {
DispatchQueue.main.async { completion(nil) }
}
} // end of task (closure)
task.resume()
}
}
答案 2 :(得分:0)
您应该在collectwhilecond(f,cond,itr) = begin
t = Base.promote_op(f,eltype(itr)) # unofficial and subject to change
r = Vector{t}()
all( x -> ( y=f(x) ; cond(y) ? (push!(r,y) ; true) : false), itr )
return r
end
内创建卡片实例,并在为其分配值后将卡片附加到for loop
数组中,方法allCard
应更新如下。
gorCards()
答案 3 :(得分:0)
您可以像这样处理URLSession dataTask的完成:
typealias Completion = (Void) -> Void
添加到您的班级为getCards方法添加完成处理程序
func getCards(completion: Completion? = nil) {}
现在你可以这样调用这个方法:
self.getCards() {
print(self.allCard.count)
}
在dataTask完成后调用completion()
导入UIKit class ViewController:UIViewController {
typealias Completion = (Void) -> Void
var allCard = [Card]()
let card = Card(name: "", cost: 0, attack: 0, durability: 0, cardClass: "", cardSet: "", imageURL: "", goldenImageURL: "", type: "", mechanics: [["":""]], howToGetGolden: "")
override func viewDidLoad() {
super.viewDidLoad()
getCards() {
print(allCard.count)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getCards(completion: Completion? = nil) {
let url = URL(string: "https://omgvamp-hearthstone-v1.p.mashape.com/cards/sets/Classic?mashape-key=....")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil { // if urlSession have issues manage the error here
print(error)
} else { // if we have data, response, error then continue here
if let urlContent = data { // if data exist then
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [Dictionary<String, AnyObject>]
for cards in 0...jsonResult.count - 1 {
if let name = jsonResult[cards]["name"] as? String { //NAME Optionaml Bindings
self.card.name = name
} else {
self.card.name = ""
} // END Name Optionaml Bindings
if let cost = jsonResult[cards]["cost"] as? Int { //COST Optionaml Bindings
self.card.cost = cost
} else {
self.card.cost = 0
} // END COST Optionaml Bindings
if let attack = jsonResult[cards]["attack"] as? Int { //ATTACK Optionaml Bindings
self.card.attack = attack
} else {
self.card.attack = 0
} // END TTACK Optionaml Bindings
} catch { //catch error while parsing json
print("error")
}
}
} // end if/ELSE
completion?()
} // end of task (closure)
task.resume()
}
}