1

Is there a good way to call an external method after a set time limit for completing the long process outlined below? I would like the long process to stop trying after a set interval and call a method to try something else and wrap up the request.

dispatch_async(dispatch_get_global_queue(0, 0), ^{

    //// LONG PROCESS

    dispatch_async(dispatch_get_main_queue(), ^{

        //// RESULTS PROCESS

    });
});
rmaddy
  • 314,917
  • 42
  • 532
  • 579
user1145643
  • 896
  • 5
  • 15
  • 26
  • 1
    Can you tell us about the nature of the long process? – tsnorri Nov 11 '14 at 20:02
  • 2
    I would recommend using an NSOperationQueue. – brandonscript Nov 11 '14 at 20:07
  • It's searching through data. I'm sure there are other ways of going about firing the method call from within the process, but I'm looking for the cleanest and most universal way tied into the code above. – user1145643 Nov 11 '14 at 20:09
  • The answer depends upon the nature of the "search". Searching some local database? Network requests? Geo search? a little more detail might be helpful. – Rob Nov 11 '14 at 21:25

3 Answers3

4

In order to "kill" the process that's running your block, you'll have to check a condition. This will allow you to do cleanup. Consider the following modifications:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

  BOOL finished = NO;
  __block BOOL cancelled = NO;
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    if (!finished) {
      cancelled = YES;
    }
  });

  void (^cleanup)() = ^{
    // CLEANUP
  };

  //// LONG PROCESS PORTION #1
  if (cancelled) {
    cleanup();
    return;
  }

  //// LONG PROCESS PORTION #2
  if (cancelled) {
    cleanup();
    return;
  }

  // etc.

  finished = YES;

  dispatch_async(dispatch_get_main_queue(), ^{

    //// RESULTS PROCESS

  });
});
Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • Same concern as the other answer. Is there a way to double back and cancel `dispatch_after` before it fires and checks the condition? – user1145643 Nov 11 '14 at 20:31
  • I'm not sure what you mean. If the `dispatch_after` fires after you've finished processing, it sees that `finished` is `YES`, so it just exits and does nothing. – Ian MacDonald Nov 11 '14 at 20:41
  • Right. But, it's left lingering until it reaches the time specified. Is that eating away system resources needlessly? If this were in a loop, this could be bad news bears... Just curious if there is a good way to cancel the condition checking function's execution before it is called. – user1145643 Nov 11 '14 at 20:45
  • You cannot cancel `dispatch_after` items. I'm not sure this particular one would eat many resources; I didn't profile it, so I'm not 100% sure, but it's not doing much. Presumably if you're expecting the processing in the rest of this process to be long enough on average to necessitate a timeout `dispatch_after`, you won't be calling it many times in a loop. – Ian MacDonald Nov 11 '14 at 20:50
3

In the ////Long Process change a boolean value (like BOOL finished) to true when finished. After the call to dispatch_async(...) you typed here, add this:

int64_t delay = 20.0; // In seconds
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^(void){
    if (!finished) {
        //// Stop process and timeout
    }
});

In this way, after 20 seconds (or any time you want) you can check if the process is still loading and take some provisions.

  • Looks good, only problem is that if the process does finish, this still checks `if(!finished)` after 20 seconds. This could cause problems in a loop situation. – user1145643 Nov 11 '14 at 20:20
  • `dispach_after` will fire off that void function to check the boolean "finished" , would there be a way to double back and terminate the request to fire off that function before it happens? To clean up? – user1145643 Nov 11 '14 at 20:34
  • Oh right. In that case the answer from Ian MacDonald is a very good choice! – Francesco Frascà Nov 11 '14 at 20:38
0

I've used this method for Swift:

let delay = 0.33 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

dispatch_after(time, dispatch_get_main_queue()) {
     //// RESULTS PROCESS   
}
CodeOverRide
  • 4,431
  • 43
  • 36