0

我对 iOS 中的多线程非常陌生,并且在执行我的任务时遇到了一些困难。我真的很感谢更有经验的程序员的任何帮助。

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

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

我创建了一个自定义异步操作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由于index out of range,即使我尝试访问串行队列中的所有属性。

这是一个数据源代码:

    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)
    }
4

0 回答 0