0

I'm working async queued processes and I need to update a counter to keep track of the progress.

This is an example close to my code (I am not posting my actual code cause it works with callbacks for specific library and it isn't really the point):

var downloadGroup = dispatch_group_create()

counter = Float(0)
total = Float(urls.count)

var myData = [MyData]()

for url in urls {
    dispatch_group_enter()
    process.doAsync(url) {
       // Success callback called on main thread

       data in

       myData.append(data) // Append data from url to an array

       counter++  // Here counter should increment for each completed task, but it doesn't update
       progressCallback(completedPercentage: counter/total)
       dispatch_group_leave(downloadGroup)
    }
}

dispatch_group_notify(downloadGroup, dispatch_get_main_queue()) {
    if myData.count == urls.count {
       println("All data retrieved")
    }
}

To put this code in words, it basically just download stuff from network, and add it to an array. Only when all data is downloaded, the last part of the code dispatch_group_notify() is called.

The interesting part is that myData.count == urls.count returns true, which means the closure is executed, but counter is always 0. My wild guess would be that [] is thread-safe while Int isn't.

How can I solve this issue? I already tried this and this and it doesn't work.

Community
  • 1
  • 1
Christopher Francisco
  • 15,672
  • 28
  • 94
  • 206

1 Answers1

0

Why don't use an NSLock to prevent multiple threads attempting access to your 'critical section'. You can even get rid of the dispatch group Do it like this:

let lock = NSLock()
counter = 0 // Why was this a float shouldn't it be an Int?
total = urls.count // This one too?

var myData = [MyData]()

for url in urls {
    dispatch_group_enter()
    process.doAsync(url) { data in
       // Since this code is on the main queue, fetch another queue cause we are using the lock.
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
          lock.lock()
          myData.append(data) // Append data from url to an array
          ++counter
          // Check inside the critical section only.
          if myData.count == urls.count {
               println("All data retrieved")
               // Do your stuff here get the main queue if required by using dispatch_async(dispatch_get_main_queue(), { })
          }
          lock.unlock()
       })
       // Do the rest on the main queue.
       progressCallback(completedPercentage: counter/total)
    }
}
Manav Gabhawala
  • 997
  • 9
  • 10