1

I have a basic beep sound that I loaded with AVAudioPlayer in my app.

It can play the beep fine if my finger isn't panning my MKMapView.

My beep is set to play every 2 seconds.

When I start panning the map view, and don't take my finger off the screen, the beep stops playing.

I recall NSUrlConnection also doesn't fire while scrolling a table view, I thought this might be the same problem but I couldn't figure out how I can add my audio player to the proper run loop.

I setup my player like this:

-(void)setupBeep
{
    NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/beep.mp3", [[NSBundle mainBundle] resourcePath]]];

    NSError *error;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    audioPlayer.numberOfLoops = 0;

    if(error)
    {
        NSLog(@"Error opening sound file: %@", [error localizedDescription]);
    }
}

and I am playing my sound like this:

// plays a beeping sound
-(void)beep
{
    [audioPlayer play];
}

Anyone came across this problem before?

Zhang
  • 11,549
  • 7
  • 57
  • 87

1 Answers1

1

How have you scheduled your -beep method to be called?

I suspect you’ve added an NSTimer to the main run loop in the default input mode. The reason you’re not hearing anything is that while MKMapView is tracking your finger, the run loop is in not in NSDefaultRunLoopMode—it’s in UITrackingRunLoopMode.

Try scheduling in NSRunLoopCommonModes, which includes both default and tracking modes:

NSTimer *timer = [NSTimer timerWithTimeInterval:interval target:self selector:@selector(beep) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Also, be aware that NSTimer retains its target. A repeating timer will reschedule itself automatically, so you’ll need to call its -invalidate method to remove it from the loop and allow the target to be released.

EDIT: Check out Apple’s Threading Programming Guide: Run Loops for a much more detailed explanation.

Ryder Mackay
  • 2,900
  • 18
  • 29
  • I am using [self performSelector:@selector(checkUserInRange:) withObject:nil afterDelay:2.0]; if user is within range, I call [self beep]; then I call [self performSelector:@selector(checkUserInRange:) withObject:nil afterDelay:2.0]; again at the end of my checkUserInRange: method. I might revert back to using NSTimer and add it to the commons run loop now that you have showed me how it is done. – Zhang Nov 24 '12 at 06:09
  • Cool, reverted back to it and included your run loop code, seems to work fine, although there is a slight pause when it tries to play the beep sound but it's a minor nuisance that I think we can live with. Thanks :) – Zhang Nov 24 '12 at 06:16