我对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)
}
}
我不知道为什么:
当我运行该应用程序时,屏幕冻结。即使我所有的队列都在后台(qos:实用程序)。
有时,当我尝试滚动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)
}