How do I post a NSNotification when using Grand Central Dispatch?

I found that as predicted when I was writing an image to file that my UI was blocked for the duration, which was not acceptable. When I write the image to file I then post an NS Notification so that I can do some other specific jobs related to that completion. Original working but UI blocking code:

-(void)saveImageToFile {
    NSString *imagePath = [self photoFilePath];
    BOOL jpgData = [UIImageJPEGRepresentation([[self captureManager] stillImage], 0.5) writeToFile:imagePath atomically:YES];

if (jpgData) {        
    [[NSNotificationCenter defaultCenter] postNotificationName:kImageSavedSuccessfully object:self];
}

To avoid the UI blocking I have put the writeToFile: into a Grand Central Dispatch queue so it runs as a concurrent thread. But when the write is completed and the thread is done, I want to post an NSNotification. I cannot as the code is shown here because it is in a background thread. But that is the functionality I want to accomplish, realizing this is not workable code:

  • How to prompt user for text input in Alert view
  • How to resign first responder from text field when user tap elsewhere?
  • How to get phone number from address book as string?
  • Taking Screenshots in the background (iOS) - Improving Performance
  • Workaround on the threads limit in Grand Central Dispatch?
  • No suitable application records were found
  • -(void)saveImageToFile {
        NSString *imagePath = [self photoFilePath];
    
        // execute save to disk as a background thread
        dispatch_queue_t myQueue = dispatch_queue_create("com.wilddogapps.myqueue", 0);
        dispatch_async(myQueue, ^{
            BOOL jpgData = [UIImageJPEGRepresentation([[self captureManager] stillImage], 0.5) writeToFile:imagePath atomically:YES];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (jpgData) {        
                [[NSNotificationCenter defaultCenter] postNotificationName:kImageSavedSuccessfully object:self];
                }
            });
        });
    }
    

    What is the correct mechanism here to post this notification to gain the functionality I want ?

    2 Solutions Collect From Internet About “How do I post a NSNotification when using Grand Central Dispatch?”

    A couple possibilities here.

    1)

    How about [NSObject performSelectorOnMainThread: …] ?

    E.G.

    -(void) doNotification: (id) thingToPassAlong
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:kImageSavedSuccessfully object:thingToPassAlong];
    }
    
    -(void)saveImageToFile {
        NSString *imagePath = [self photoFilePath];
    
        // execute save to disk as a background thread
        dispatch_queue_t myQueue = dispatch_queue_create("com.wilddogapps.myqueue", 0);
        dispatch_async(myQueue, ^{
            BOOL jpgData = [UIImageJPEGRepresentation([[self captureManager] stillImage], 0.5) writeToFile:imagePath atomically:YES];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (jpgData) {   
                    [self performSelectorOnMainThread: @selector(doNotification:) withObject: self waitUntilDone: YES];
                }
            });
        });
    }
    

    More details at http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorOnMainThread:withObject:waitUntilDone:

    or 2)

    Completion Callbacks

    as seen at How can I be notified when a dispatch_async task is complete?

    -(void)saveImageToFile {
        NSString *imagePath = [self photoFilePath];
    
        // execute save to disk as a background thread
        dispatch_queue_t myQueue = dispatch_queue_create("com.wilddogapps.myqueue", 0);
        dispatch_async(myQueue, ^{
            BOOL jpgData = [UIImageJPEGRepresentation([[self captureManager] stillImage], 0.5) writeToFile:imagePath atomically:YES];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (jpgData) {        
                [[NSNotificationCenter defaultCenter] postNotificationName:kImageSavedSuccessfully object:self];
                }
            });
        });
    }
    

    That is already correct. However why do you need to use notification if you already dispatch_get_main_queue()?

    Just use

            dispatch_async(dispatch_get_main_queue(), ^{
                if (jpgData) {        
                //Do whatever you want with the image here
                }
            });
    

    Anyway your original solution is fine. It’s not blocking. Basically it’ll save the file at other thread and once it’s done it’ll do what it takes.

    What ever you do will be done on the same thread with the thread that call [[NSNotificationCenter defaultCenter] postNotificationName:kImageSavedSuccessfully object:self]; namely main thread.