10

I have a voip application which runs constantly on the background as well. While I'm in the background I'm calling from the main thread: (to establish network connection in case I diagnose a network lost).

[self performSelector :@selector(Reconnect:) withObject:nil afterDelay:60.0];

However, the selector is only performed when my app returns to foreground. Should I do anything in particular to make the selector getting executed while in the background ?

Thanks

Edit:

-(void) reconectInBackgroundAfterDelay:(NSTimeInterval) dealy
{
    NSLog(@"reconectInBackgroundAfterDelay");
    UIApplication*   app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [self performSelector :@selector(Reconnect:) withObject:nil afterDelay:dealy];

        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

I added this code instead, but still the "Reconnect" method is not getting called after the provided delay. I call the "reconectInBackgroundAfterDelay" method while I'm already in the background.

Any other suggestions ?

Edit 2 Found a solution. See below

Idan
  • 5,717
  • 10
  • 47
  • 84

3 Answers3

22

The only solution I found so far :

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

        NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:1 target:self  selector:@selector(Reconnect:) userInfo:nil repeats:NO];    

        [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];

        [[NSRunLoop currentRunLoop] run]; 
    }); 
Idan
  • 5,717
  • 10
  • 47
  • 84
  • My application is also voip application. But initially my app shoulld download files from server before register. Is it possible to continue downloading using your solution. – Khushbu Shah Feb 13 '13 at 10:40
  • Here is [http://stackoverflow.com/questions/14828955/download-files-using-http-request-in-background-in-iphone-above-ios-4-0#comment20777172_14828955] [My question] – Khushbu Shah Feb 13 '13 at 10:41
  • I assume this code replaces the dispatch_async block in your question. Is that correct? Could you post the full code solution just to be clear? – Josh Brown Mar 13 '13 at 14:28
  • Additionally, where's the -beginBackgroundTaskWithExpirationHandler:? Isn't that necessary for running in the background? – Josh Brown Mar 13 '13 at 14:33
  • @JoshBrown Yes, this solution is replacement for only dispatch block. Idan already coded his -beginBackgroundTaskWithExpirationHandler, see above. – REALFREE Mar 20 '13 at 05:10
  • Great approach! Do you know if it also passes Apple's AppStore Approval Process? – JohannesRu Mar 30 '14 at 19:37
  • 1
    The NSRunLoop class is generally not considered to be thread-safe and its methods should only be called within the context of the current thread. You should never try to call the methods of an NSRunLoop object running in a different thread, as doing so might cause unexpected results. – Prasad De Zoysa Jul 08 '14 at 10:31
1

I was test it for some time, found that in ios background run when an corebluetooth event coming, if you want to do something delay use NSTimer object,you must be less than 10 seconds, and if more than 10 seconds, the timer will be invalid.

DDZ
  • 11
  • 2
  • 1
    what is the significance of 10 seconds here? can you please explain it in a logical way? – Swamy Jul 04 '13 at 04:39
  • Sorry for the late reply, let me give an example see the following code, if DELAY_EVENT_TIME more than 10, this doSomething func will not be called #define DELAY_EVENT_TIME 8 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { [NSTimer scheduledTimerWithTimeInterval:DELAY_EVENT_TIME target:self selector:@selector(doSomething) userInfo:nil repeats:NO]; } - (void)doSomething { NSLog(@"doSomething delay!"); } – DDZ Jul 27 '13 at 11:08
1

Have you put this line in the beginBackgroundTaskWithExpirationHandler block? Have a look at th section Completing a Finite-Length Task in the Background at http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html.

Akshay
  • 5,747
  • 3
  • 23
  • 35
  • I'm not using a background task, my app is a voip application so it can run constantly in the background, keeping a persistent network connection. Don't see a reason using a background task here, can't see how it would help either. – Idan Oct 09 '11 at 14:06
  • VoIP applications don't run constantly in the background. From the [iOS Application Programming Guide](http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH5-SW15): "Rather than keep VoIP applications awake all the time, the system allows them to be suspended and provides facilities for monitoring their sockets for them. When incoming traffic is detected, the system wakes up the VoIP application and returns control of its sockets to it." – omz Oct 09 '11 at 14:33
  • Ok, then let's say I lost my tcp connection in the background, and I want to schedule a selector after 2 minutes to reestablish the connection. If performselectorafterdelay won't do it, how should I achieve it ? obviously background task is not suitable here. – Idan Oct 09 '11 at 14:57
  • Unless there's a way to schedule background tasks, which I'm not aware of. – Idan Oct 09 '11 at 14:58
  • `performSelectorAfterDelay` will do it (will be executed) if you put it inside the background task block. – Akshay Oct 09 '11 at 15:44