Creating a continuous background thread in iOS

15,065

Solution 1

Unless there is some specific reason this has to be a discrete thread, I would recommend you use an GCD or an NSOperation Queue and produce and consume workers. This kind of long-running thread is going to be a real problem in an iOS app.

GCD tutorial:

http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial

Solution 2

I have implemented a similar scenario to what you describe. The way it was implemented was to have a continuous timer running on a background thread.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        notification = [[NotificationCentre alloc] init];

        notificationTimer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(notificationTimerFired:) userInfo:nil repeats:YES];

        [[NSRunLoop currentRunLoop] run]; 

    });
    [self.window makeKeyAndVisible];

    return YES;
}

-(void)notificationTimerFired:(NSTimer *)theTimer {
    BOOL hasNotifications;

    if (notificationTimerActive == YES) {

        do {
            hasNotifications = [notification GetNotifications];
        } while (hasNotifications == YES);

    }

    return;

}

So basically when the app is launched I start a repeating timer async, then call my GetNotifications method on my noticiationCenter class.

Share:
15,065
Abishek
Author by

Abishek

Experienced and an influential Technical Leader and Architect, an inspirational leader who effectively manages, develops and motivates internal & external teams. Strong ability to quickly understand and analyze business strategies ensuring technology solutions meet business requirement, to quickly adapt to all new technologies & challenges. Attention to detail, high technical aptitude and hands on approach together with a high degree of motivation and professionalism would make me an asset to any progressive organization or demanding position within IT industry. I spend a lot of time learning new stuff and I enjoy doing it.

Updated on June 27, 2022

Comments

  • Abishek
    Abishek almost 2 years

    I have a requirement to create a background processor that works only when the App is in the active mode. I have tried to make a skelton of what I am trying to acheive but not able to get it to work.

    I want this background Processor to go to sleep when the app goes to an inactive stage and resume when the app comes to an active mode. I have provided a skeleton of what I have done below. Can someone help me fix this.

    AppDelegate.h

    #import <Foundation/Foundation.h>
    
    @class BackgroundProcessor;
    
    @interface AppDelegate_iPhone : UIResponder<UIApplicationDelegate>{
        BackgroundProcessor* processor;
    }
    
    @property(nonatomic) BackgroundProcessor *processor;
    
    @end
    

    AppDelegate.m

    #import "AppDelegate_iPhone.h"
    #import "BackgroundProcessor.h"
    
    
    @implementation AppDelegate_iPhone
    
    @synthesize processor;
    
    -(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        processor = [[BackgroundProcessor alloc]init];
        [processor Start];         
        return YES;
    }
    
    -(void) applicationDidEnterBackground:(UIApplication *)application
    {
        [processor Sleep];
        NSLog(@"Entered Background"); 
    }
    
    -(void) applicationDidBecomeActive:(UIApplication *)application
    {
        [processor Resume];
        NSLog(@"Became Active"); 
    }
    @end
    

    BackgroundProcessor.h

    #import <Foundation/Foundation.h>
    
    @interface BackgroundProcessor : NSObject
    {
        NSThread* processor;
    }
    
    @property (nonatomic) NSThread *processor;
    
    -(void) Start;
    -(void) Sleep;
    -(void) workloop;
    -(void) Resume;
    @end
    

    BackgroundProcessor.m

    #import "BackgroundProcessor.h"
    
    @implementation BackgroundProcessor
    @synthesize processor;
    -(id) init
    {
        self = [super init];
        if(self)
        {
            processor = [[NSThread alloc] initWithTarget:self selector:@selector(workloop) object:nil];
        }
        return self;
    }
    
    -(void) Start
    {
        if(processor)
            [processor start];
    }
    
    -(void) Sleep
    {
        //    [processor 
        [NSThread sleepForTimeInterval: 0.1];
    }
    
    -(void) workloop
    {
        NSLog(@"Background Processor Processing ....");  
        [NSThread sleepForTimeInterval:0.1];
    }
    
    - (void) Resume
    {
        NSLog(@"Background Resuming ....");  
        [NSThread sleepForTimeInterval: 0.1];
    }
    

    I am not able to get the workloop to get it running continuosly. Appreciate if someone could help me solve why the background

    Tried this after the advice from Joshua Smith

    #import "BackgroundProcessor.h"
    
    @implementation BackgroundProcessor
    
    -(id) init
    {
        self = [super init];
        if(self)
        {
            queue = [[NSOperationQueue alloc] init];
            NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(workloop) object:nil];
            [queue addOperation:operation];
        }
        return self;
    }
    
    -(void) workloop
    {
    
        NSLog(@"Sleeping for 10 seconds");  
        sleep(10);
        NSLog(@"Background Processor Processing ....");  
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(workloop) object:nil];
        [queue addOperation:operation];
    }
    
    @end
    
  • Duncan C
    Duncan C almost 12 years
    I agree with Joshua. In general, you want to avoid creating your own threads. Threads tie up physical memory and critical system resources. GCD is a much more efficient way to manage concurrent execution, and it's easier to use to boot.
  • Abishek
    Abishek almost 12 years
    I basically want to spawn a thread that keeps checking the DB periodically to send data from my app to the server. What would you recommend an ideal option to do something like this. Is there an article or code something that I can refer to, to have a workaround instead of spawning my own threads? And this operation needs to happen only when the application is on the Foreground or in the Active mode.
  • Abishek
    Abishek almost 12 years
    Well, I wanted this to happen only when the App is on the Foreground or Active State and not in the Background/Inactive state.
  • Joshua Smith
    Joshua Smith almost 12 years
    developer.apple.com/library/mac/#documentation/Cocoa/Referen‌​ce/… is the best place to start. What you would want to do, at a high level, is put jobs in the queue (to check the DB) and refill the queue when it starts to run out of operations. you can do the same thing with GCD.
  • Abishek
    Abishek almost 12 years
    I like the approach that you have suggested, to keep re-filling the queue with operations. Is there any performance issues when one does this? What number of operations do you suggest for refilling every time?
  • mlindy92
    mlindy92 almost 12 years
    Then the app should automatically happen, if you want to make sure you could release the background processor when you enter the background and when the application becomes active again you can reinitialize the object
  • Joshua Smith
    Joshua Smith almost 12 years
    There are no performance issues specifically with this, and the number of operations to use depends entirely on how fast they are used, how much memory they take, etc. Optimizing queue fills like this can take some tweaking (it's a hard problem).
  • Abishek
    Abishek almost 12 years
    Edited and Added a working solution to my question. Also, I use ARC, so I feel I should not be worrying about the memory as well. Can you advice if it is good enough a solution?
  • Joshua Smith
    Joshua Smith almost 12 years
    I would add a check in your loop to check if the job has been cancelled and/or if the queue itself has been cancelled (there are examples in the NSOperationQueue doc for that).
  • Abishek
    Abishek almost 12 years
    Not sure if I understand you completely. When you say if the job has been cancelled did you mean by the current operation? How can i access the object of the current operation? Do you want me to get the 1 item from [queue operations] and check with that (Because there is always going to be only one job at a time)?