1

我知道这些NSTimer问题已经出现了很多次,但是由于似乎没有一个涉及执行更改 UI 的块,我认为这仍然是一个原始问题。

我有一个子类UIButton,为了方便起见(我,来自Android背景),有一个onClickonHoldClick功能。onClick只需获取一个块并在响应的选择器中执行它UIControlEventTouchUpInside。点击功能很好用。例如:

[myButton setOnClick:^{
    NSLog(@"clicked");
}];

保持点击功能效果不佳。

[myButton setOnHoldClick:^{
    NSLog(@"still holding click...");
}];

这会监听UIControlEventTouchDown事件,并在延迟后执行任务:

- (void)clickDown:(id)sender
{
    isClicked = YES;

    [self performSelector:@selector(holdLoop:) withObject:nil afterDelay:delay];//For the sake of the example, delay is set to 0.5  
}

保持循环在另一个函数上运行一个重复的计时器,该函数处理块执行(计时器变量是NSTimer在头文件中声明的):

-(void)holdLoop:(id)sender
{
    [self cancelTimers];
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(death:) userInfo:nil repeats:YES];
}

-(void)death:(id)_delay
{

    if (isClicked)
    {
        _holdBlock();
    }
    else
    {
        [self cancelTimers];

    }
}

执行的块会改变浮点数的值,用于更新标签的值,然后重新绘制。

第一次发生按住单击事件时,效果很好。在那之后,似乎计时器没有被取消,并且仍然添加了新的计时器。这就是我的cancelTimers函数的样子(这里的调用是从关于这个主题的其他问题的集合中检索的):

-(void)cancelTimers
{
    [_timer invalidate];
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(death:) object:nil];
}

我做错了什么,我该如何解决?

编辑

我做的,其实里面已经有响应touch up的功能了:

- (void)clickUp:(id)sender
{
    isClicked = NO;
    [self cancelTimers];
    _clickBlock();
}

此外,我意识到问题来自未处理的取消事件。iOS 是否有理由自动取消我的长按?

4

2 回答 2

2

Solved

Since the block redrew the UI, it was also redrawing the buttons (and resetting their functionality). This event was causing a cancel event to be called on the button - which was not handled. Adding the following:

[self addTarget:self action:@selector(cancelClick:) forControlEvents:UIControlEventTouchCancel];
[self addTarget:self action:@selector(cancelClick:) forControlEvents:UIControlEventTouchUpOutside];


-(void)cancelClick:(id)sender
{
    isClicked = NO;
    [self cancelTimers];
}

As well as reconsidering what changes are made in the block, has gotten me past this issue.

于 2013-06-04T15:33:49.353 回答
1

As I understood from the comments and the code, the clickDown: is called for UIControlEventTouchDown so isClicked is set to YES when the first time the button is touched down. You need to add a selector to the event UIControlEventTouchUpInside. It's called when the user lifts his finger while being iside the bound of the button. Inside that method, set isClicked to NO.

于 2013-06-04T15:18:41.433 回答