簡體   English   中英

在DispatchGroup中執行完成處理程序

[英]Execute Completion Handler in DispatchGroup

我想在UITableView顯示服務器延遲,唯一的問題是ping結果處理程序不會在DispatchQueue下運行

let dispatch_queue = DispatchQueue(label: "PingQueue", qos: .background)
            dispatch_queue.async {
                let client = SimplePingClient()
                client.pingHostname(hostname: self.Servers[indexPath.row].Address, andResultCallback: { result in
                    guard let r = result as? String else {
                        DispatchQueue.main.async {
                            cell.lblLatency.text = "Timeout"

                        }
                        return
                    }
                    DispatchQueue.main.async{
                        cell.lblLatency.text = r + " ms"
                    }
                })
            }

andResultCallback不會調用(我不知道為什么!?)

首先,您應該注意一些有關現有代碼的事情。

  1. 您對dispatch_queue.async的調用正在執行client初始化,並且對client.pingHostname的調用在dispatch_queue.async隊列上運行。 請注意,因為pingHostname是異步API,所以它幾乎立即返回,並不意味着競爭處理程序將在dispatch_queue運行。

    • 請注意,使用dispatch_queue.async可能沒有任何意義。 假設客戶端初始化是一個輕量級的,不依賴IO的任務(即,它不執行任何自身的網絡調用),並假設pingHostname是輕量級的(鑒於它是其自身的異步功能,則幾乎可以肯定是這樣),那么就沒有理由為什么不能使用dispatch_queue.sync調用,甚至不能直接從當前線程進行這些調用。 它可能幾乎一樣快,甚至可能更快(因為異步調用使轉義分析變得更加困難,並限制了編譯器的優化)。 這樣做還有一個好處,那就是消除了“如果在下一個事情之前完成此操作?或者如果相反則要做什么?”的擔心。
  2. 您提供了一個異步pingHostname API的閉包,它可以在所需的任何線程/隊列上自由運行,我們稱其為queue / thread X API文檔可能會對此有所啟發。

  3. 從隊列/線程X的上下文中,您對DispatchQueue.main進行異步調用。 這是對的; 可可的目的是使所有UI更新必須始終在主線程中進行。

如果您聲明的意圖是在dispatch_queue上運行競爭處理程序代碼,則您必須:

  1. 提供pingHostname API的dispatch_queue作為參數,以便它可以在您的隊列上運行競爭處理程序,而不是采用其他默認值。 當然,這是API必須具有的功能。

  2. 在競爭處理程序中,從線程/隊列X調用自己的dispatch_queue.sync

在沒有DispatchQueue參數的情況下,這是我的寫法:

pingQueue = DispatchQueue(label: "PingQueue", qos: .background)

let client = SimplePingClient()
client.pingHostname(
    hostname: self.Servers[indexPath.row].Address, // This is jank, but I'm ignoring it for now
    andResultCallback: { _latency in
        pingQueue.sync {
            print("Do some stuff on pingQueue")

            DispatchQueue.main.sync { // enter main queue for UI updates
                cell.lblLatency.text = (_latency as? String).map { $0 + " ms" } ?? "Timeout"
            }
        }
    }
)

cellForRowAt內部調用此方法是不正確的。 您應該在ViewController結果數組中的某處

var results = [String]()

現在,在別的地方獲取結果,而不是在cellForRowAt 為此創建自定義方法,或使用自定義模型。

更好的方法是,如果您的pingHostname方法返回所有結果,然后您只分配results數組,然后重新加載TableView的數據

client.pingHostname { results in
    if let r = result as? [String] {
        self.results = r
        self.tableView.reloadData()
    } 
}

也將此results數組用作TableView數據源方法的源

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return results.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    cell.lblLatency.text = results[indexPath.row]
    ...
}

不會調用結果回調,因為在完成操作之前,您的ping客戶端已被釋放。

使client成為實例變量而不是局部變量。 完成后將其設置為nil

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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