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);
}
}
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.