简体   繁体   English

带有NSTimer的UIGestureRecognizer永不消亡

[英]UIGestureRecognizer with NSTimer that never dies

I'm trying to set up a "FastForward/Next" button in a media player that can be tapped to move to the next song or held to fast forward within the current song. 我正在尝试在媒体播放器中设置“快进/下一首”按钮,可以轻按此按钮以移至下一首歌曲,也可以按住以在当前歌曲中快进。 Mostly, it works: you can successfully fastforward and successfully move to the next song, but the thing is, the NSTimer that makes it work never invalidates, so once you start fastforwarding, you never stop. 通常,它是可行的:您可以成功地进行快进并成功移至下一首歌曲,但实际上,使它起作用的NSTimer永远不会失效,因此一旦开始快进就不会停止。

I set up the gesture recognizers in viewDidLoad : 我在viewDidLoad设置了手势识别器:

UITapGestureRecognizer *singleTapFastForward = [[UITapGestureRecognizer alloc] initWithTarget: self action:@selector(nextSong:)];
singleTapFastForward.numberOfTapsRequired = 1;
[_buttonNext addGestureRecognizer:singleTapFastForward];

_holdFastForward = [[UILongPressGestureRecognizer alloc] initWithTarget: self action:@selector(startFastForward:)];
[_buttonNext  addGestureRecognizer:_holdFastForward];
[singleTapFastForward requireGestureRecognizerToFail:_holdFastForward];

and here is the meat of the function: 这是函数的内容:

- (IBAction)startFastForward:(id)sender {
    _timerFastForward = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(executeFastForward) userInfo:nil repeats:YES];
}

- (void)executeFastForward {
    [_avPlayer seekToTime:CMTimeMake(CMTimeGetSeconds([_avPlayer currentTime]) + 10, 1)];
    if(_holdFastForward.state == 0) {
        [self endFastForward:self];
    }
}

- (IBAction)endFastForward:(id)sender {
    [_timerFastForward invalidate];
}

Here's the tricky part: when I set a breakpoint at the if(_holdFastForward.state == 0) line, it starts working as soon as I let go of the button (as it should), and it successfully calls the endFastForward method. 这是棘手的部分:当我在if(_holdFastForward.state == 0)行上设置断点时, if(_holdFastForward.state == 0)我放开按钮(应有的话),它就会开始工作,并成功调用endFastForward方法。 By my reckoning, that should kill the timer and end the whole cycle, but then executeFastForward gets called again, and then again and again. 据我估计,这应该杀死计时器并结束整个周期,但是然后再次调用executeFastForward ,然后一次又一次。 The invalidate line just seems to do nothing (and there are no other points in my code that call executeFastForward ). invalidate行似乎什么也没做(在我的代码中没有其他点调用executeFastForward )。

Any ideas? 有任何想法吗? This seems like a simple thing, and if the invalidate line worked everything would be perfect. 这似乎是一件简单的事情,并且如果invalidate行有效,那么一切都会很完美。 I just don't know why executeFastForward continues to be called. 我只是不知道为什么executeFastForward继续被调用。 Is my NSTimer TRON's answer to the Highlander, or is there something else going on? 我的NSTimer TRON是对Highlander的回答,还是有其他事情发生?

NSTimer takes selector that should take one parameter as NSTimer * , here is the cite from Apple's documentation NSTimer采用选择器,该选择器应采用一个参数作为NSTimer * ,这是Apple 文档中的引用

The selector must correspond to a method that returns void and takes a single argument. 选择器必须对应于返回void并接受单个参数的方法。 The timer passes itself as the argument to this method. 计时器将自身作为此方法的参数传递。

Try to change the signature of your executeFastForward method like this: 尝试像这样更改executeFastForward方法的签名:

-(void) executeFastForward:(NSTimer *)timer

than you can invalidate the timer passed as an argument, which will actually be the fired timer object 那么您可以使作为参数传递的计时器无效,该计时器实际上将是触发的计时器对象

Well, after a LOT of experimentation (and being inspired by the if statement in this answer to an unrelated but similar question) I finally found a solution: don't check for the end of the gesture in the executeFastForward method, but rather the startFastForward method. 好吧,经过大量的实验(并受到与无关但相似的问题的答案中if语句的启发),我终于找到了解决方案:不要在executeFastForward方法中检查手势的executeFastForward ,而要检查startFastForward方法。 Also, it turns out the startFastForward method was being called over and over, re-creating the timer, so the if statement also stops that by restricting the timer to UIGestureRecognizerStateBegan . 而且,事实证明, startFastForward调用了startFastForward方法,重新创建了计时器,因此if语句还通过将计时器限制为UIGestureRecognizerStateBegan来停止了该操作。

Here's the working code, for anyone who wants it: 这是工作代码,适用于任何需要的人:

- (IBAction)startFastForward:(UIGestureRecognizer *)gestureRecognizer {
    if(gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        _timerFastForward = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(executeFastForward) userInfo:nil repeats:YES];
    } else if(gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        [self endFastForward:self];
    }
}

- (void)executeFastForward {
    [_avPlayer seekToTime:CMTimeMake(CMTimeGetSeconds([_avPlayer currentTime]) + 10, 1)];
}

- (IBAction)endFastForward:(id)sender {
    [_timerFastForward invalidate];
    _timerFastForward = nil;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM