1

I have an operation queue setup as follows:

let queue = OperationQueue()
queue.name = "com.company.myQueue"
queue.qualityOfService = .userInitiated
queue.maxConcurrentOperationCount = 64
...
var current = 0
var totalCount = someArray.count
for i in someArray {
... 
   let op = BlockOperation {
   ... // do some database queries
   current += 1
   }

   op.completionBlock = {
     DispatchQueue.main.async {
     let nData: [String: CGFloat] = ["value": CGFloat(current/totalCount)]
     NotificationCenter.default.post(name:Notification.Name(rawValue: "update"), object: nil, userInfo: nData)
   }

   queue.addOperation(op)
}

In my ViewController I listen for the notification and update a UILabel with the percentage. Problem is though I don't get any intermediate values... it jumps from being 0 directly to 100 once all the operations are done.

What am I doing wrong?

Thanks

Joseph
  • 9,171
  • 8
  • 41
  • 67
  • Unrelated, but I might suggest `extension Notification.Name { static let update = Notification.Name(rawValue: "update") }`. Then you can do things like `NotificationCenter.default.post(name: .update, object: nil, userInfo: nData)`. And I’d advise against a `maxConcurrentOperation` count of 64, because you can easily exhaust the limited number of worker threads if you do that. You should generally stay below 64. – Rob May 28 '20 at 15:59

2 Answers2

1

You can move your notification send function directly in op.completionBlock (without dispatching it in main thread).

Edit (comments) :

let queue = OperationQueue()
    queue.name = "com.company.myQueue"
    queue.qualityOfService = .userInitiated
    queue.maxConcurrentOperationCount = 64

let array = ["", "", "", "", "", ]

var current = 0
var totalCount = array.count

for _ in array {
    let op = BlockOperation { current += 1 ; print(current) }
        op.completionBlock = {
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: Notification.Name(rawValue: "update"), object: nil, userInfo: ["value": CGFloat(current / totalCount)])
            }
        }

   queue.addOperation(op)
}

NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "update"), object: nil, queue: nil) { (notification) in
    print(notification.userInfo)
}

Edit 2 (comments) : You should make your percentage by float casting current and totalCount before dividing them.

CGFloat(current) / CGFloat(totalCount)
'''
Magiguigui
  • 151
  • 2
  • 13
1

The problem is CGFloat(current / totalCount). That does the integer math first, and then converts it to a float. You should flip that around to CGFloat(current) / CGFloat(totalCount).

Rob
  • 415,655
  • 72
  • 787
  • 1,044