我最初使用GCD,但每次用户通过点击按钮过滤图表数据时,需要重新计算图表数据,如果用户非常快速地点击图表数据过滤按钮(超级用户),那么图表会循环显示每个图纸每个GCD调度异步完成
我意识到我不能用GCD取消线程所以我已经开始试图实现一个OperationQueue
我在向队列添加新 *** 作之前调用cancelAllOperations()
队列上的 *** 作很时髦,有时似乎它们被取消了,有时似乎完成的那个不是最新的队列.
我也无法取消正在执行的 *** 作,因为当我在 *** 作完成块中检查它时, *** 作的.isCancelled属性永远不会为真
我真正想要的是,如果图表数据计算当前正在后台线程中发生,并且用户单击另一个过滤器按钮并在后台线程上启动另一个图表计算,则先前的图表后台线程计算将终止并“替换”为最近添加了 *** 作
这可能吗?
这是一些代码:
func setHistoricalChart() -> VoID { self.lineChartVIEw.clear() self.lineChartVIEw.noDataText = "Calculating Historical Totals,Please Wait..." self.historicalOperationsQueue.qualityOfService = .utility self.historicalOperationsQueue.maxConcurrentoperationCount = 1 self.historicalOperationsQueue.name = "historical operations queue" let historicalOperation = Operation() historicalOperation.completionBlock = { [weak self] in //dictionary of Feeds,array of data for each Feed var valuesByFeed = [String:[String]?]() var dates = [String:[String]?]() var chartDataSets = [IChartDataSet]() //get data and values from DataMOs in the activeFeeds if (self?.activeFeeds.count)! > 0 { //check if operation is cancelled if historicalOperation.isCancelled { return } for (key,Feed) in (self?.activeFeeds)! { dates[key] = Feed?.datas?.flatMap({ Utils.formatUTcdateString(utcdateString: (解决方法var item: dispatchWorkItem!item = dispatchWorkItem { ... while notYetDone() { if item.isCancelled { os_log("canceled") return } ... } os_log("finished")}let queue = dispatchQueue(label: Bundle.main.bundleIDentifIEr! + ".customQueue")queue.async(execute: item)// just to prove it's cancelable,let's cancel it one second laterdispatchQueue.main.asyncAfter(deadline: .Now() + 1) { os_log("canceling") item.cancel()}as! DataMO).utcdateString) }) valuesByFeed[key] = Feed?.datas? .sorted(by: { ((OperationQueue
as! DataMO).utcdateString)! < (( as! DataMO).utcdateString)! }) .flatMap({ (let operation = BlockOperation()operation.addExecutionBlock { ... while notYetDone() { if operation.isCancelled { os_log("canceled") return } ... } os_log("finished")}let queue = OperationQueue()queue.maxConcurrentoperationCount = 1queue.addOperation(operation)// just to prove it's cancelable,let's cancel itdispatchQueue.main.asyncAfter(deadline: .Now() + 1) { os_log("canceling") operation.cancel()}as! DataMO).value }) } //Create Chart Data for (key,valuesArray) in valuesByFeed { var dataEntrIEs = [ChartDataEntry]() for (index,value) in (valuesArray?.enumerated())! { let dataEntry = ChartDataEntry(x: Double(index),y: Double(value)!) dataEntrIEs.append(dataEntry) } let singleChartDataSet = lineChartDataSet(values: dataEntrIEs,label: key) singleChartDataSet.drawCirclesEnabled = false switch key { case "Solar": singleChartDataSet.setcolors(UIcolor(red: 230/255,green: 168/255,blue: 46/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 230/255,Alpha: 0.8) break case "Wind": singleChartDataSet.setcolors(UIcolor(red: 73/255,green: 144/255,blue: 226/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 73/255,Alpha: 0.8) break case "Battery": singleChartDataSet.setcolors(UIcolor(red: 126/255,green: 211/255,blue: 33/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 126/255,Alpha: 0.8) break case "Gen": singleChartDataSet.setcolors(UIcolor(red: 208/255,green: 1/255,blue: 27/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 208/255,Alpha: 0.8) break case "Demand": singleChartDataSet.setcolors(UIcolor(red: 128/255,green: 133/255,blue: 233/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 128/255,Alpha: 0.8) break case "Prod": singleChartDataSet.setcolors(UIcolor(red: 241/255,green: 92/255,blue: 128/255,Alpha: 1)) singleChartDataSet.drawFilledEnabled = true singleChartDataSet.fillcolor = UIcolor(red: 241/255,Alpha: 0.8) break default: break } chartDataSets.append(singleChartDataSet) } } //check if operation is cancelled if historicalOperation.isCancelled { return } //set chart data let chartData = lineChartData(dataSets: chartDataSets) //update UI on MainThread OperationQueue.main.addOperation({ if (self?.activeFeeds.count)! > 0 { self?.lineChartVIEw.data = chartData } else { self?.lineChartVIEw.clear() self?.lineChartVIEw.noDataText = "No Feeds To Show" } }) } historicalOperationsQueue.cancelAllOperations() historicalOperationsQueue.addOperation(historicalOperation)}
I realize that I can’t cancel threads with GCD …
除此之外,这并不完全正确.您可以取消分派到GCD队列的dispatchWorkItem项:
class Chartoperation: Operation { var Feeds: [Feed] private var chartoperationCompletion: (([IChartDataSet]?) -> VoID)? init(Feeds: [Feed],completion: (([IChartDataSet]?) -> VoID)? = nil) { self.Feeds = Feeds self.chartoperationCompletion = completion super.init() } overrIDe func main() { let results = [IChartDataSet]() while notYetDone() { if isCancelled { OperationQueue.main.addOperation { self.chartoperationCompletion?(nil) self.chartoperationCompletion = nil } return } ... } OperationQueue.main.addOperation { self.chartoperationCompletion?(results) self.chartoperationCompletion = nil } }}
不可否认,您必须取消单个dispatchWorkItem实例,但它确实有效.
… so I’ve moved to trying to implement an
let operation = Chartoperation(Feeds: activeFeeds) { results in // update UI here}queue.addOperation(operation)
不幸的是,这还没有正确实施.简而言之,您的问题中的代码是创建一个在 *** 作本身中不执行任何 *** 作的 *** 作,而是在其完成处理程序中具有所有计算密集型代码.但是只有在 *** 作“完成”后才会调用此完成处理程序.已完成的 *** 作(即已经运行完成处理程序的 *** 作)无法取消.因此, *** 作将忽略取消这些正在进行的,耗时的完成处理程序块的尝试.
相反,创建一个块 *** 作,并将您的逻辑添加为“执行块”,而不是完成处理程序.然后取消按预期工作:
或者,甚至可能更好,创建一个执行此工作的Operation子类. Operation和OperationQueue的优点之一是您可以从视图控制器代码中解开复杂的 *** 作代码.
例如:
我不知道你的activeFeeds是什么,所以我把它声明为一个Feed数组,但你可以根据需要进行调整.但它说明了同步 *** 作的想法:只需子类 *** 作并添加一个main方法.如果要将数据传递给 *** 作,请将其作为参数添加到init方法.如果要传回数据,请添加一个闭包参数,该参数将在 *** 作完成时调用.注意,我更喜欢这依赖于内置的completionHandler,因为它没有提供像上面的自定义完成处理程序那样提供传递给闭包的参数的机会.
无论如何,您的视图控制器可以执行以下 *** 作:
和上面的例子一样,这是可以取消的.
顺便说一句,虽然我展示了如何确保 *** 作是可取消的,但您可能还需要确保在各种for循环中检查isCancelled(或者可能只是在最深层嵌套的for循环中).事实上,你在过程的早期检查isCancelled,如果你以后不检查它,它将忽略后续的取消.调度和 *** 作队列不执行抢先取消,因此您必须在要识别取消的任何位置插入isCancelled检查.
总结以上是内存溢出为你收集整理的ios – 无法取消OperationQueue swift中的执行 *** 作全部内容,希望文章能够帮你解决ios – 无法取消OperationQueue swift中的执行 *** 作所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)