1

我该怎么办?

我有一个 UISwitch。当用户点击开关时,惊人的事情发生了!

现在,如果用户双击开关,我就有了惊人的崩溃!因为第一个水龙头还在做着惊人的事情!

我想做的是这个,

用户水龙头:

1 -调用 toggleOvertimeSwitch

2 -从开关中移除目标(为了避免在发生双击时被调用)

3 -做令人惊奇的事情

4 -再次添加目标

尽管稍后需要注意 Switch 的位置,但乍一看,这应该可行。但事实并非如此。

我正在删除自己作为目标,但它仍然会不断响应所有的点击!toggleOvertimeSwith 总是被调用。我不明白为什么。

任何人都可以帮我解决这个问题吗?

谢谢!

努诺

代码:

我的 viewDidLoad 实现了这个,

[self.toggleSwitch addTarget:self
                      action:@selector(toggleOvertimeSwitch:)
            forControlEvents:UIControlEventValueChanged];

我的 toggleOvertimeSwitch 实现了这个,

-(void)toggleOvertimeSwitch:(UISwitch *)sender
{

[self.toggleSwitch removeTarget:self
                         action:@selector(toggleOvertimeSwitch:)
               forControlEvents:UIControlEventValueChanged];

// Do something amazing here


[self.toggleSwitch addTarget:self
                      action:@selector(toggleOvertimeSwitch:)
            forControlEvents:UIControlEventValueChanged];

}
4

3 回答 3

1
  • 如果您提到“做一些令人惊奇的事情”的部分与您的其余代码在同一个线程/队列中执行,它不会改变任何东西,因为每个事件/使用操作都在主线程中处理,所以从你的开始toggleOvertimeSwitch:最后,在方法本身完成之前,不会有任何中断或由任何用户操作触发的此方法的任何其他调用。

  • 如果您的“令人惊奇的事情”代码在单独的线程中执行,例如使用 GCDdispatch_async函数,那么禁用您的开关操作是有意义的,但是:

    • 在重新激活开关操作之前,您应该等待“惊人的工作”完成,就好像您确实在那里异步执行了某些操作,并且重新添加目标/操作的代码将在不等待异步代码完成的情况下执行,您的根据定义,开关将在操作完成之前重新启用
  • 而且,您应该使用enabled开关的属性来禁用和重新启用它,而不是删除和重新添加目标/动作,这会容易得多!

我不知道你是否真的使用 GCD 或一些线程代码或其他任何东西来完成你的“惊人的工作”,因为你没有在你的问题中提供太多信息,所以我只是完全猜测,但如果你使用例如 dispatch_async ,它会给出这样的东西:

-(IBAction)toggleOvertimeSwitch:(UISwitch*)sender
{
    // disable the switch
    sender.enabled = NO;

    // start your long background work
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, 0), ^{
      // ... some amazing work in the background, executed asynchronously ...

      // Then, when finished, re-enable the switch:
      dispatch_sync(dispatch_get_main_queue(), ^{
        sender.enabled = YES;
      });
    });
}

PS:同样,如果您不使用在后台执行的任何线程或异步代码,而是使用在当前线程中同步执行的代码,那么您的问题根本不存在,因为您的所有toggleOvertimeSwitch:方法只会在一步不中断,之后才会处理下一个 UI 事件(触摸等)。

于 2012-10-01T23:04:28.887 回答
1

在你的doSomethingAmazing:方法开始时,说

mySwitch.userInteractionEnabled = NO;

...然后作为最后一件事doSomethingAmazing

mySwitch.userInteractionEnabled = YES;

这将防止您的目标/动作选择器再次被触发,直到您准备好为止。

于 2014-11-21T09:59:07.620 回答
0

我的猜测是,addTarget并且removeTarget不会立即发生,因为您的假设在这里,而是在稍后发生的线程上排队。一个更好的方法,而不是删除目标并重新添加它,是确保你的“做一些惊人的事情”的方法是线程安全的。您可能需要将属性更改为原子,或使用其他一些同步机制。

如果您要提供更多关于您在“惊人”方法中所做的事情以及崩溃到底是什么的详细信息,我们可能会在那里发现一些东西。

于 2012-10-01T22:49:08.043 回答