[英]How to wait for Swift's URLSession to finish before running again?
可能是一個愚蠢的問題,但是我是一個初學者。
以下代碼應該通過關鍵字搜索從Google圖書中獲取圖書信息。 然后,它檢查結果並檢查Firebase數據庫中是否有匹配的ISBN。 可以,但是目前只能搜索40本書,因為這是每次搜索最多可以使用Google Books API。
幸運的是,我可以指定從何處開始索引並獲取接下來要搜索的40本書。 不幸的是,我已經嘗試了幾個小時來了解URLSession的工作原理。 我嘗試過的所有方法都向我展示了URLSession塊之后的代碼不必等待會話完成。 因此,如果我檢查之后是否找到任何匹配項,則可能甚至無法完成搜索。
我懷疑答案是在完成處理中,但是到目前為止,我的嘗試均未成功。 以下是我的代碼,其中包含使用各種起始索引值的URL設置。
var startingIndex = 0
//encode keyword(s) to be appended to URL
let query = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let url = "https://www.googleapis.com/books/v1/volumes?q=\(query)&&maxResults=40&startIndex=\(startingIndex)"
URLSession.shared.dataTask(with: URL(string: url)!) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}else{
let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: AnyObject]
if let items = json["items"] as? [[String: AnyObject]] {
//for each result make a book and add title
for item in items {
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
let book = Book()
//default values
book.isbn13 = "isbn13"
book.isbn10 = "isbn10"
book.title = volumeInfo["title"] as? String
//putting all authors into one string
if let temp = volumeInfo["authors"] as? [String] {
var authors = ""
for i in 0..<temp.count {
authors = authors + temp[i]
}
book.author = authors
}
if let imageLinks = volumeInfo["imageLinks"] as? [String: String] {
book.imageURL = imageLinks["thumbnail"]
}
//assign isbns
if let isbns = volumeInfo["industryIdentifiers"] as? [[String: String]] {
for i in 0..<isbns.count {
let firstIsbn = isbns[i]
if firstIsbn["type"] == "ISBN_10" {
book.isbn10 = firstIsbn["identifier"]
}else{
book.isbn13 = firstIsbn["identifier"]
}
}
}
//adding book to an array of books
myDatabase.child("listings").child(book.isbn13!).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
if listings.contains(book) == false{
listings.append(book)
}
DispatchQueue.main.async { self.tableView.reloadData() }
}
})
myDatabase.child("listings").child(book.isbn10!).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
if listings.contains(book) == false{
listings.append(book)
}
DispatchQueue.main.async { self.tableView.reloadData() }
}
})
}
}
}
}
SVProgressHUD.dismiss()
}.resume()
以下是我的修改代碼:
func searchForSale(query: String, startingIndex: Int) {
directionsTextLabel.isHidden = true
tableView.isHidden = false
listings.removeAll()
DispatchQueue.main.async { self.tableView.reloadData() }
SVProgressHUD.show(withStatus: "Searching")
//clear previous caches of textbook images
cache.clearMemoryCache()
cache.clearDiskCache()
cache.cleanExpiredDiskCache()
let url = "https://www.googleapis.com/books/v1/volumes?q=\(query)&&maxResults=40&startIndex=\(startingIndex)"
URLSession.shared.dataTask(with: URL(string: url)!) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}else{
var needToContinueSearch = true
let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: AnyObject]
if json["error"] == nil {
let totalItems = json["totalItems"] as? Int
if totalItems == 0 {
SVProgressHUD.showError(withStatus: "No matches found")
return
}
if let items = json["items"] as? [[String: AnyObject]] {
//for each result make a book and add title
for item in items {
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
let book = Book()
//default values
book.isbn13 = "isbn13"
book.isbn10 = "isbn10"
book.title = volumeInfo["title"] as? String
//putting all authors into one string
if let temp = volumeInfo["authors"] as? [String] {
var authors = ""
for i in 0..<temp.count {
authors = authors + temp[i]
}
book.author = authors
}
if let imageLinks = volumeInfo["imageLinks"] as? [String: String] {
book.imageURL = imageLinks["thumbnail"]
}
//assign isbns
if let isbns = volumeInfo["industryIdentifiers"] as? [[String: String]] {
for i in 0..<isbns.count {
let firstIsbn = isbns[i]
//checks if isbns have invalid characters
let isImproperlyFormatted = firstIsbn["identifier"]!.contains {".$#[]/".contains($0)}
if isImproperlyFormatted == false {
if firstIsbn["type"] == "ISBN_10" {
book.isbn10 = firstIsbn["identifier"]
}else{
book.isbn13 = firstIsbn["identifier"]
}
}
}
}
//adding book to an array of books
myDatabase.child("listings").child(book.isbn13!).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
if listings.contains(book) == false{
listings.append(book)
needToContinueSearch = false
}
DispatchQueue.main.async { self.tableView.reloadData() }
}
})
myDatabase.child("listings").child(book.isbn10!).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
if listings.contains(book) == false{
listings.append(book)
needToContinueSearch = false
}
DispatchQueue.main.async { self.tableView.reloadData() }
return
}
if startingIndex < 500 {
if needToContinueSearch {
let nextIndex = startingIndex + 40
self.searchForSale(query: query, startingIndex: nextIndex)
}
}
})
}
}
}
}else{
return
}
}
SVProgressHUD.dismiss()
}.resume()
//hide keyboard
self.searchBar.endEditing(true)
}
聲明一個bool變量為isLoading,如果該函數正在加載,則不要觸發urlsession。 希望下面的樣本對您有幫助。
var isLoading : Bool = false
func loadMore(with pageCount: Int){
if isLoading { return }
isLoading = true
// call the network
URLSession.shared.dataTask(with: URL(string: "xxxxx")!) { (data, response, error) in
// after updating the data set isloding to false again
// do the api logic here
//
DispatchQueue.main.async {
// self.items = downloadedItems
self.tableView.reloadData()
self.isLoading = false
}
}.resume()
}
在完成處理程序中,如果返回任何結果,則以:
DispatchQueue.main.async { self.tableView.reloadData() }
觸發使用更新的信息重新加載表。 此時,您可以確定可能會有更多結果,並啟動下一個異步URL任務。 概述中,您的代碼可能是:
let needToContinueSearch : Bool = ...;
DispatchQueue.main.async { self.tableView.reloadData() }
if needToContinueSearch
{ // call routine it initiate next async URL task
}
(如果有任何理由要從主線程啟動任務,則if
將在塊中。)
在處理完第一個搜索的結果之后才開始下一個搜索,從而避免了必須處理與上一個搜索同時更新數據的后續回調的任何問題。
但是,如果您發現以這種方式延遲第二次搜索的速度太慢,則可以研究重疊操作的方式,例如,您可能讓回調函數僅將結果的處理傳遞給串行隊列上的異步任務(因此,只有一組的結果立即被處理)並啟動下一個異步URL任務。
HTH
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.