Question

How to preform certain operation in background on different thread, if it is executed on main thread it is blocking the UI of my app. any one have any idea how to do it?

even if it prints NSLog in background it will be fine. i want to run following thing in no matter even if user presses HOME button. in my viewController i did this :

- (IBAction)btnStartClicked:(UIButton *)sender {
    [NSThread detachNewThreadSelector:@selector(StartBGTask) toTarget:self withObject:nil];
     }

-(void)StartBGTask{
    [[[UIApplication sharedApplication] delegate] performSelector:@selector(startThread)];  
  }

and in appDelegate.m i have this method

 -(void) startThread {
 @autoreleasepool {
    for (int i = 0; i < 100; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"current progress %d", i);
        });
        [NSThread sleepForTimeInterval:1];
    }
   }
 }

it prints integer from 1 to 100 on interval of 1 second.

Was it helpful?

Solution

Add these properties to your .h file

@property (nonatomic, strong) NSTimer *updateTimer;
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;

Now replace btnStartClicked method with this,

-(IBAction)btnStartClicked:(UIButton *)sender {
    self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
                                                        target:self
                                                      selector:@selector(calculateNextNumber)
                                                      userInfo:nil
                                                       repeats:YES];
    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"Background handler called. Not running background tasks anymore.");
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        self.backgroundTask = UIBackgroundTaskInvalid;
    }];
    
}

 -(void)calculateNextNumber{
    @autoreleasepool {
      // this will be executed no matter app is in foreground or background
    }
}

and if you need to stop it use this method,

 - (IBAction)btnStopClicked:(UIButton *)sender {

    [self.updateTimer invalidate];
    self.updateTimer = nil;
    if (self.backgroundTask != UIBackgroundTaskInvalid)
    {
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        self.backgroundTask = UIBackgroundTaskInvalid;
    }
    i = 0;
}

OTHER TIPS

Check GCD for more information.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //code in background
    });

A really easy way to accomplish what you want:

-(IBAction)btnStartClicked:(UIButton *)sender {
   [self performSelectorInBackground:@selector(codeInBakground) withObject:nil];
}

-(void)codeInBakground
{
   for (int i = 0; i < 100; i++) {
         NSLog(@"current progress %d", i);
        [NSThread sleepForTimeInterval:1]; //the code will print one number in each second, until 100
    }
}

In this way, your main thread, and your UI won't be blocked.

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