Dispatch Group inside NSOperation - Still allowing multiple operations despite maxConcurrentOperationCount = 1

百般思念 提交于 2019-12-02 02:49:31

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!