2

Hello I am new to iPhone development so I could be doing this all wrong. I want to convert an image 3 times in a row but when I do it locks up the iphone until it finishes all 3 conversions. I have functions between the steps but they will not fire until the last image convert fires. This make more more sense if you read the code Notes below.

My questions are

  1. Is there a faster way to convert the images? 2. How do I stop it from locking up so that it fires the code in order and the functions between the image converts fire inline?

    - (IBAction)ColorFun1
    {
        //  
        // ANY CODE IN THIS location will not fire until 3rd convert is finished 
        // 
        // Image to convert 
        UIImage *originalImage = imageView.image;   
    
        // 1st Convert 
    
        CGColorSpaceRef colorSapce = CGColorSpaceCreateDeviceGray();
        CGContextRef context = CGBitmapContextCreate(nil, originalImage.size.width,     originalImage.size.height, 8, originalImage.size.width, colorSapce, kCGImageAlphaNone);
        CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
        CGContextSetShouldAntialias(context, NO);
        CGContextDrawImage(context, CGRectMake(0, 0, originalImage.size.width, originalImage.size.height), [originalImage CGImage]);
        CGImageRef bwImage = CGBitmapContextCreateImage(context);
        //
        CGContextRelease(context);
        CGColorSpaceRelease(colorSapce);
        //
        UIImage *resultImageBW = [UIImage imageWithCGImage:bwImage]; // This is result B/W image.
        [fxImage2View setImage:resultImageBW];
    
    
    
        //  
        // ANY CODE IN THIS location will not fire until 3rd convert is finished 
    
        // 
    
        //  
        // 
        // 2nd Convert 
    
        // 
    
        UIGraphicsBeginImageContext(resultImageBW.size);
    
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy);
    
        [resultImageBW drawInRect:CGRectMake(0, 0, resultImageBW.size.width, resultImageBW.size.height)];
    
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeDifference);
    
    
        CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(),[UIColor grayColor].CGColor);
    
        CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, resultImageBW.size.width, resultImageBW.size.height));
    
        UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext();
        [fxImage1View setImage:returnImage];
        UIGraphicsEndImageContext();    
    
        //
        //
    
        //   
        // ANY CODE IN THIS location will not fire until 3rd convert is finished 
        // 
        // 
    
        // 
        // 3rd Convert 
    
        // 
    
        UIGraphicsBeginImageContext(resultImageBW.size);
    
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy);
    
        [resultImageBW drawInRect:CGRectMake(0, 0, resultImageBW.size.width, resultImageBW.size.height)];
    
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(),   kCGBlendModeSoftLight);
    
    
        CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(),[UIColor colorWithRed:40 green:20 blue:0 alpha:1].CGColor);
    
        CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, resultImageBW.size.width, resultImageBW.size.height));
    
        returnImage = UIGraphicsGetImageFromCurrentImageContext();
        [fxImage3View setImage:returnImage];
        UIGraphicsEndImageContext();    
    
        CGImageRelease(bwImage);
    
    }
    
Kunadiso
  • 71
  • 1
  • 4

2 Answers2

2

You need to transfer control back to the run loop like sergio says. I'd suggest looking into grand central dispatch. From wikipedia

Grand Central Dispatch still uses threads at the low level but abstracts them away from the programmer, who will not need to be concerned with as many details. Tasks in GCD are lightweight to create and queue; Apple states that 15 instructions are required to queue up a work unit in GCD, while creating a traditional thread could easily require several hundred instructions

It shouldn't be too hard to find a tutorial on how to implement it. You might even consider the Stanford dev lectures. This one talks about performance & threading. I think the part thats relevant to you starts at 33:36.

Manish Burman
  • 3,069
  • 2
  • 30
  • 35
0

I think that your issue depends on the fact that since you are doing a bunch of processing without returning control back to the main loop, your UI is not updated in between.

One possibility you have is defining three methods, each one doing one image conversion (this will also help readability of your code). Then you can call them in a way that between calls flow control gets back to the main loop and UI is updated.

As an example, if your 3 methods are convertImage1, convertImage2, and convertImage3, you can do:

[self performSelector:@selector(convertImage1) withObject:nil afterDelay:0];
[self performSelector:@selector(convertImage2) withObject:nil afterDelay:0];
[self performSelector:@selector(convertImage3) withObject:nil afterDelay:0];

The same effect can be obtained in a cleaner way if you use Grand Central Dispatch dispatch_async method to dispatch your call:

dispatch_async(dispatch_get_main_queue(), ^{ [self convertImage1]; });
dispatch_async(dispatch_get_main_queue(), ^{ [self convertImage2]; });
dispatch_async(dispatch_get_main_queue(), ^{ [self convertImage3]; });

There are many design variables that you can tweak here; this is just an example to give you an idea.

sergio
  • 68,819
  • 11
  • 102
  • 123