Question

I am calling the code below from within the AppDelegate:

-(void) application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {


-(BOOL)backgroundRefresh{
    newData = false;
    callStartTime = [NSDate date];

    [self processAll];
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while(!fetchComplete);
        NSLog(@"NOW COMPLETE");

   });
    NSLog(@"Got here now!");
    return newData;
}

The call to [self processAll] runs code that has async calls etc, and will keep looping around until all activities are complete, repeatedly calling itself. Once all tasks are complete, fetchComplete is set to true. This part works fine.

I need the code to wait for fetchComplete to be true, and then return a bool back to AppDelegate.

The issue is, that quite rightly, the current checking, whilst it works to show the NSLogs etc., is of no use to returning the BOOL back to the caller, as the process is currently async. I have set it to async so that it runs, otherwise, I find that the processAll code is being blocked from running.

Could someone please shed some light onto how I can monitor for fetchComplete, and only once that is true return the bool to the calling function?

I have tried moving the return to into the async block, after the while has returned, but this returns a syntax error due to calling within the block.

Was it helpful?

Solution

Use a notification. First, you must start listening to the notification like this

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(fetchDidComplete)
                                             name:@"fetchDidComplete"
                                           object:nil];

Where ever you set fetchComplete to true, post a notification like this

[[NSNotificationCenter defaultCenter] postNotificationName:@"fetchDidComplete"
                                                    object:self
                                                  userInfo:nil];

Then you should have a method called fetchDidComplete that will do the post completion work. Don't forget to stop listening to the notification once done.

[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:@"fetchDidComplete"
                                              object:nil];

OTHER TIPS

You don't wait for an async process to finish. That makes it synchronous. You need to change your thinking.

There are a number of different ways to handle async APIs.

  1. Pass in a completion block
  2. Assign a delegate and define a method that gets called on completion.
  3. Send a notification when the process completes.

There are no doubt more, but the whole idea of an async API is that it returns immediately, and you DON'T wait for it to finish. As the other person said, never, ever, use code like while(!fetchComplete). That is a seriously bad idea.

The manor of which you are trying to solve this problem is a bit atypical.

Generally this is done with either delegation, blocks or notifications.

The idea being you only want to perform some function after the completion of some asynchronous method.

Let's say we have an asyc processor called AyncProcessor.

AyncProcessor * processor = [AyncProcessor sharedProcessor];
processor.delegate = self;
[processor start];

is a fairly common way to do the delegation. The assumption here is that there is a protocol defined with a callback method that is run upon completion.

//protocol method
-(void) processingComplete;

// and at some point in AsyncProcessor
[self.delegate processingComplete] 

more info on delegation here

Blocks can be used as well

AyncProcessor * processor = [AyncProcessor sharedProcessor];
[processor start:^()/{
  ///code in this block will complete after processing has completed
 }];

more info on blocks can be found here

And as already shown you can send a NSNotification.

For your problem delegation is likely a good idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top