问题
I am aiming for a serial download queue within NSOperation subclass using dispatch groups to manage async tasks.
I have maxConcurrentOperationCount set to 1
i have defined my queue
var GlobalDownloadQueue: DispatchQueue {
return DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
}
Then inside main() of NSOperation subclass i have defined my dispatch group, have 3 enters and 3 leaves, then a notify block.
The notify block seems to be running at the right time, however there is still multiple instances of the NSOperation running at once.
This is what the console is printing when i select 2 downloads.
[0, 3] : Enter : 1
[0, 2] : Enter : 2
[0, 3] : Enter : 2
[0, 2] : Enter : 3
[0, 2] : Leave : 1
[0, 2] : Leave : 2
QUEUE FINISHED
[0, 2] : Leave : 3
[0, 3] : Enter : 3
[0, 3] : Leave : 1
[0, 3] : Leave : 2
[0, 3] : Leave : 3
QUEUE FINISHED
This is what it looks like when i select 1 download:
[0, 0] : Enter : 1
[0, 0] : Enter : 2
[0, 0] : Enter : 3
[0, 0] : Leave : 1
[0, 0] : Leave : 2
[0, 0] : Leave : 3
QUEUE FINISHED
So it is at least making the thread synchronous, its still just allowing more than 1 operation to run at a time. I thought maxConcurrentOperationCount = 1 would only allow 1 operation to run from the queue until the main() function of NSOperation subclass was complete?
This is how i add items to the queue
self.downloadQueue.addOperation(DownloadOperation(index: indexPath))
And then my main() function inside NSOperation:
override func main() {
// this is async because using the enter and leave should make it essentially serial??
GlobalDownloadQueue.async() {
let downloadGroup = DispatchGroup()
let downloadedAudio = PFObject(className: "downloadedAudio")
let selectedObjectId = GlobalOperationStore.sharedInstance.globalMultiPartArray[self.collectionView.tag][self.indexPath.item].id
let selectedPartName = GlobalOperationStore.sharedInstance.globalMultiPartArray[self.collectionView.tag][self.indexPath.item].name
downloadGroup.enter() // add task 1
print("\(self.indexPath) : Enter : 1")
let query = PFQuery(className: "Part")
query.whereKey("objectId", equalTo: selectedObjectId)
query.getFirstObjectInBackground { (object, error) in
if error != nil || object == nil {
print("No object for the index selected.")
//downloadGroup.leave() // remove task 1 if error with query
} else {
//print("there is an object, getting the file.")
downloadedAudio.add(object?.object(forKey: "partAudio") as! PFFile, forKey: selectedPartName)
let downloadedFile = object?.object(forKey: "partAudio") as! PFFile
downloadGroup.enter() // add task 2
print("\(self.indexPath) : Enter : 2")
// get the data first so we can track progress
downloadedFile.getDataInBackground({ (success, error) in
if (success != nil) {
downloadGroup.enter() // add task 3
print("\(self.indexPath) : Enter : 3")
// pin the audio if there is data
downloadedAudio.pinInBackground(block: { (success, error) in
if success {
//if (DownloadCollectionController().isViewLoaded && (DownloadCollectionController().view.window != nil)) {
// viewController is visible
/// maybe has to be operation main queue
self.mainQueue.addOperation {
// reload the cell
self.collectionView.reloadItems(at: [self.indexPath])
self.collectionCell.isUserInteractionEnabled = true
}
downloadGroup.leave() // remove task 1 when complete
print("\(self.indexPath) : Leave : 1")
downloadGroup.leave() // remove task 2 when complete
print("\(self.indexPath) : Leave : 2")
downloadGroup.leave() // remove task 3 when complete
print("\(self.indexPath) : Leave : 3")
//}
}
})
}
}, progressBlock: { (percent) in
self.mainQueue.addOperation {
//print("\(downloadedFile.name)::::\(percent)")
//self.activityIndicatorView.stopAnimating()
if let downloadingCell = self.collectionView.cellForItem(at: self.indexPath) as? InnerCollectionCell {
downloadingCell.progressBar.isHidden = false
downloadingCell.contentView.bringSubview(toFront: downloadingCell.progressBar)
downloadingCell.progressBar.setProgress(Float(percent) / Float(100), animated: true)
downloadingCell.setNeedsDisplay()
downloadingCell.isUserInteractionEnabled = false
}
}
})
}
}
downloadGroup.notify(queue: GlobalDownloadQueue, execute: {
print("QUEUE FINISHED")
})
} // async
}
来源:https://stackoverflow.com/questions/41995439/dispatch-group-inside-nsoperation-still-allowing-multiple-operations-despite-m