views:

27

answers:

1

Hi,

I am trying to implement a (non-concurrent) NSOperation for location updates using the iPhone SDK. The "meat" of the NSOperation subclass goes something like this:

- (void)start {
    // background thread set up by the NSOperationQueue
    assert(![NSThread isMainThread]);

    if ([self isCancelled]) {
        return;
    }

    self->locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = self->desiredAccuracy;
    locationManager.distanceFilter = self->filter;
    [locationManager startUpdatingLocation];

    [self willChangeValueForKey:@"isExecuting"];
    self->acquiringLocation = YES;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)cancel {
    if ( ! self->cancelled ) {
        [self willChangeValueForKey:@"isCancelled"];
        self->cancelled = YES;
        [self didChangeValueForKey:@"isCancelled"];

        [self stopUpdatingLocation];
    }
}

- (BOOL)isExecuting {
    return self->acquiringLocation == YES;
}

- (BOOL)isConcurrent {
    return NO;
}

- (BOOL)isFinished {
    return self->acquiringLocation == NO;
}

- (BOOL)isCancelled {
    return self->cancelled;
}



- (void)stopUpdatingLocation {
    if (self->acquiringLocation) {
        [locationManager stopUpdatingLocation];

        [self willChangeValueForKey:@"isExecuting"];
        [self willChangeValueForKey:@"isFinished"];
        self->acquiringLocation = NO;  
        [self didChangeValueForKey:@"isExecuting"];
        [self didChangeValueForKey:@"isFinished"];
    }
    locationManager.delegate = nil;
}


- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    assert(![NSThread isMainThread]);

    // ... I omitted the rest of the code from this post

    [self stopUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)theError {
    assert(![NSThread isMainThread]);
    // ... I omitted the rest of the code from this post
}

Now, on the main thread I create an instance of this operation and add it to an NSOperationQueue. The start method gets called, however none of the -locationManager:... delegate methods get called. I don't get it why they never get called.

I did make the interface adhere to the <CLLocationManagerDelegate> protocol. I'm letting the NSOperationQueue manage the thread for this operation, so it should all be conforming to the CLLocationManagerDelegate documentation:

The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.

I am not sure what else to try for this to work. Maybe it's staring me in the face... Any help is appreciated.

Thanks in advance!

+1  A: 

You are missing the "active run loop" part. At the end of your start method add:

whilie (![self isCancelled])
  [[NSRunLoop currentRunLoop] runUntilDate:someDate];

Aleph
So it *was* staring me in the face :) I didn't think I had to run the runloop manually, due to the NSOperationQueue managing the thread (and its runloop). I guess that's not the case. Thank you!
octy