Search code examples
iosobjective-cgrand-central-dispatchdispatch-async

Refer back to background queue with grand central dispatch/dispatch_async in Objective-C


I am currently trying to run a process in the background over a period of time to ensure the user can still navigate the application whilst I collect data. I have discovered that I should utilise GCD for this. However, I'm unsure how to make arrayBuild run in the background queue as well.

How do I also add this to the background queue? The application works fine when the reference to dispatch_async is removed so I know the issue is with the thread.

- (IBAction)buttonPressed:(id)sender {

    dispatch_async(backgroundQueue, ^{

        manager.delegate = self;
        manager.desiredAccuracy = kCLLocationAccuracyBest;

        /* Removed for testing
        [manager startUpdatingLocation];
         */

        // TEST

        myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                   target:self
                                                 selector:@selector(arrayBuild)
                                                 userInfo:nil
                                                  repeats:YES];

        // Initialise Array
        resultsArray = [[NSMutableArray alloc]init];

        // END TEST

    });

}

- (void)arrayBuild {

    loopCount++;

    if (loopCount >= 11) {

        // Invalidate Timer
        [myTimer invalidate];
        myTimer = nil;

        // Find Average
        NSNumber *avg = [resultsArray valueForKeyPath:@"@avg.self"];

        // Change Text of Label to Average & Log
        self.signal.text = [NSString stringWithFormat:@"%@",avg];
        NSLog(@"%@",avg);



    }else{

        // Declare Signal Strength
        float signalstrength = CTGetSignalStrength();

        // Individual Result & Convert to Integer
        NSString *result = [NSString stringWithFormat:@"%f", signalstrength];
        NSInteger resultInt = [result integerValue];

        // Add Object
        [resultsArray addObject:[NSNumber numberWithFloat:resultInt]];

        // Change Text of Label Each Second
        self.signal.text = [NSString stringWithFormat:@"%d",loopCount];
        NSLog(@"%f",signalstrength);

    }

}

Solution

  • You cannot create timers in a background queue like that. NSTimer needs a run loop and background queues generally do not have one. You could use a GCD timer source if you want a timer to fire on a custom background queue (or worse, create your own NSThread and start a run loop on that thread, and then schedule the NSTimer on that thread's run loop), but it's just going to be easier to eliminate the GCD code and just start your timer from the main run loop (i.e. don't dispatch the creation of a timer to a background queue).

    Likewise, you should configure and start the CLLocationManager location updates from the main thread, too. I don't think it causes a problem to do it like you have, but it's unnecessary.

    Timers and location updates happen asynchronously and as long as the appropriate handler runs reasonably quickly, don't worry about trying to schedule them on background queues. The main thread is generally fine.