Question

I'm having trouble firing a performSelector afterDelay command, upon detection of an accelerometer 'flick'. The movement is detected ('Got here' is logged), but for some reason the selector passed to the performSelector command is not firing.

I set up a test block, and successfully ran a performSelector from that, so I don't think blocks themselves are causing the problem, perhaps it's something to do with the thread that CoreMotion is running on? (I must admit to being slightly hazy on blocks/threads/CoreMotion)

Any clues would be much appreciated. Thanks.

- (void)viewDidLoad
{
    [super viewDidLoad];
    //Do any additional setup after loading the view, typically from a nib.

    motionManager = [[CMMotionManager alloc] init];
    if(motionManager.accelerometerAvailable)
    {
        motionManager.accelerometerUpdateInterval = 0.1;
        NSOperationQueue *motionQueue = [[NSOperationQueue alloc] init]; 
        [motionManager startAccelerometerUpdatesToQueue: motionQueue withHandler: ^(CMAccelerometerData *data, NSError *error) 
         {
             float accelerationThreshold = 1.2;

             CMAcceleration userAcceleration = data.acceleration;
             if (fabs(userAcceleration.x) > accelerationThreshold)               
             {
                 NSLog(@"Got here"); //runs
                 [self performSelector:@selector(test) withObject:nil afterDelay:1.0];
             }
         }];
    }
}

-(void) test
{
    NSLog(@"perform selector after delay worked"); //doesn't run
}
Était-ce utile?

La solution

I got there in the end (After first toying with the idea of switching to using the UIAccelerator method of accessing the accelerometer - but then discovering that this is to be deprecated in future iOS releases (See the section "Motion Event Types" here)

Basically the code in the block, executed when motion is detected, may not be run on the main thread, which can cause issues, especially with UIView related code.

The way to ensure that code is executed on the main thread is to call:

[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:false]; 

instead of the normal:

[self performSelector:@selector(test) withObject:nil afterDelay:1.0]; 

Oh, I found the solution in an google books excerpt from the excellent looking Beginning IPhone 4 Development: Exploring the IOS SDK. Hopefully this may be of some use to people struggling in the same area, feel free to comment if you'd like any more info / code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top