0

I have a function that turns out be too slow to run on main thread (200ms). This function is used to determine the size of the image.

extension : UIImage {
    var dataLengh_kb: Int {
        return (UIImageJPEGRepresentation(self, 1.0)?.length)! / 1024
    }
 }

I am using in various places of my app and especially in the following example

 func someFunction() {
    if img.dataLength_kb > MAX_SIZE {
        // Upload to server
    } else {
        someImageView.image = img
    }

    functionFinished()
 }

Since it is too slow, I am thinking to put it in background thread in two ways I am not sure what the difference and impact to my app is either way.

Method 1:

extension : UIImage {

    var size: Float!

    var dataLengh_kb: Int {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        size = UIImageJPEGRepresentation(self, 1.0)?.length)! / 1024

        dispatch_async(dispatch_get_main_queue(), ^{
            return size
        })
    })
}

Method 2:

extension : UIImage {

    var size: Float!

    var dataLengh_kb: Int {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            return UIImageJPEGRepresentation(self, 1.0)?.length)! / 1024

        dispatch_async(dispatch_get_main_queue(), ^{

        })
    })
 }

My question is

  1. If I go with method 2, does that mean all my code after dataLengh_kb will be in background thread which is bad?

  2. If I go with either method 1 or method 2, does that mean functionFinished() will be executed too early ?

  3. Both method 1 and method 2 complains that I am not returning an Int Value as it is expected to return 'Int'

user172902
  • 3,541
  • 9
  • 32
  • 75

2 Answers2

2

If I go with method 2, does that mean all my code after dataLengh_kb will be in background thread which is bad?

YES

If I go with either method 1 or method 2, does that mean functionFinished() will be executed too early ?

YES

Is Method 1 the correct way to do it ?

NO

UIImageJPEGRepresentation creates an NSData object for the respective image. It is an expensive and CPU hungry object which is not needed here, i.e. just to get size of image.

Ideal way would be :

Int imgSize  = CGImageGetHeight(image.CGImage) * CGImageGetBytesPerRow(image.CGImage)

OR

extension UIImage {

    var sizeInBytes : Int {
      return CGImageGetHeight(self.CGImage) * CGImageGetBytesPerRow(self.CGImage)
     }
}
Gurdeep
  • 171
  • 9
1

Unfortunately both methods arent going to work, and even if it was going to somehow, the if statement is dependant on the result of the function, so it would have to wait for the background thread to finish anyway... the whole thing needs to be on a background thread. So maybe this will work for you:

 func someFunction() {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
       if img.dataLength_kb > MAX_SIZE {
           // Upload to server (this should NOT be asynchronous if possible, it can block the thread at this point because we are already on a background thread and i assume functionFinished() depends on the result so it should wait here)
       } else {
           dispatch_sync(dispatch_get_main_queue()) { 
              someImageView.image = img //all UI changes must be back on the main thread
           }
       }
       dispatch_sync(dispatch_get_main_queue()) { //optional, but i assume some UI changes will happen inside this function
           functionFinished()
       }
    })
 }

disclaimer: have not tested the code so may need some tweaking

Fonix
  • 11,447
  • 3
  • 45
  • 74
  • Thanks. Why did you choose to use dispatch_sync instead of dispatch_async for the two main queue? In most cases I have used dispatch_async(dispatch_get_main_queue() in most cases but I dont really know why – user172902 Sep 22 '16 at 06:44
  • 1
    dispatch_sync means that the dispatch block gets executed immediately at that point so any code that comes afterward is guarenteed that the block has finished, while if it was dispathc_async, it would just be put on the main threads queue and executed later, which could mean that any code between `someImageView.image = img` and `functionFinished()` and after could be executed in an unexpected order – Fonix Sep 22 '16 at 06:49