簡體   English   中英

如何等待Swift的URLSession完成再重新運行?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM