iOS OperationQueue:并发异步操作阻止屏幕

时间:2019-04-09 13:57:58

标签: ios swift multithreading nsoperationqueue ios-multithreading

我对iOS中的多线程技术还很陌生,在执行任务时遇到一些困难。非常感谢经验丰富的程序员的任何帮助。

作为起点,我有一个URL地址,我向其提出请求,检查一些信息并检索该网页上包含的所有URL地址。此后,我需要一次又一次地对新的URL地址执行相同的操作,直到检查了特定数量的URL。

我决定使用 Operations OperationQueues ,因为我还需要能够选择最大数量的并发操作。

我创建了一个自定义异步操作LoadOperation,并将其应用于存储在数组中的每个URL。在完成块中,我将新的URL添加到数组中,并递归地调用相同的函数。

我还创建了两个队列:

  • 并发请求,

  • 用于访问共享属性的串行序列,如下所示:
class Queue<Item: Equatable> {

    // concurrent queue for URL-requests
    let loadOperationQueue = OperationQueue() // qos: .utilities

    // serial operation queue for accessing shared properties 
    let serialOperationQueue = OperationQueue() // qos: .utilities

    // maximum number of URLs that need to be checked ultimately
    var maxNumberOfItems: Int = 1

    var pendingItems: [Item] = []   // newly added URLs
    var loadingItems: [Item] = []   // loading URLs
    var processedItems: [Item] = [] // URLs that were checked

    // all URLs for tableView dataSource
    var allItems: [Item] {
        return processedItems + loadingItems + pendingItems
    }

    func addToPending(_ item: Item) {
        guard allItems.count < maxNumberOfItems else {return}
        pendingItems.append(item)
    }

    func removeFromPending() -> Item? {
        guard !self.pendingItems.isEmpty else { return nil }
        let item = pendingItems.removeFirst()
        loadingItems.append(item)
        return item
    }

    func addToProcessed(_ item: Item) {
        loadingItems = loadingItems.filter{$0 != item}
        processedItems.append(item)

    }

    func isFull() -> Bool {
        return allItems.count >= maxNumberOfItems
    }
}

这是我的搜索功能:

    func startSearching() {

        // iterate over array of URLs creating async operation
        while let currentWebPage = queue.removeFromPending() {

            let loadOperation = LoadOperation(currentWebPage, searchString: searchString)

            loadOperation.completionBlock = {
                let webPage = loadOperation.output!

                self.queue.serialOperationQueue.addOperation {

                    // add checked URL to processed
                    self.queue.addToProcessed(webPage)

                    // add new urls to an array of pending URLs
                    for urlString in webPage.containedLinks {
                        //check if the limit of checked urls is not exceeded
                        guard !self.queue.isFull() else { return }
                        //check if this url is already in queue
                        guard !self.queue.allItems.contains(where: {$0.url == urlString}) else { continue }

                        self.queue.addToPending(WebPage(url: urlString, containedLinks: [], status: .pending))
                    }

                    // update UI
                    OperationQueue.main.addOperation {
                        self.viewDelegate?.reloadTable()
                    }

                    // repeat searching process with new urls
                    self.startSearching()
                }
            }
            queue.loadOperationQueue.addOperation(loadOperation)
        }

    }

我不知道为什么:

  1. 当我运行该应用程序时,屏幕冻结。即使我所有的队列都在后台(qos:实用程序)。

  2. 有时,当我尝试滚动UITableView时,由于索引超出范围,我得到sigabort,即使我尝试访问串行队列中的所有属性。

这是数据源代码:

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "WebPageTableViewCell", for: indexPath) as! WebPageTableViewCell
        let (url, status) = presenter.getCellContent(at: indexPath.row)
        cell.addressLabel.text = url
        cell.statusLabel.text = status
        return cell
    }

还有presenter中的函数:

    func getNumberOfRows() -> Int {
        return queue.allItems.count
    }

    func getCellContent(at index: Int) -> (url: String, status: String) {
        return (url: queue.allItems[index].url, status: queue.allItems[index].status.description)
    }

0 个答案:

没有答案