iOS7 UISwitch其事件ValueChanged:不断调用是这个Bug或什么..?

编辑

它现在固定在ios7.1上
不要做任何调整来解决它。

EDIT2

显然,iOS 8.0和8.1中也会出现同样的问题

EDIT3

它现在固定在ios9.2上
不要做任何调整来解决它。


嗨今天,我看到在UISwitch's事件ValueChanged: continuously调用,而我正在改变到OnOffOff到开,我的手指仍然在右侧和左侧移动。 我使用NSLog来更清晰地呈现GIF图像。

在这里输入图像说明

我的价值改变方法是:

 - (IBAction)changeSwitch:(id)sender{ if([sender isOn]){ NSLog(@"Switch is ON"); } else{ NSLog(@"Switch is OFF"); } } 

iOS6的开关工作相同的代码正如我们所期望的那样:

在这里输入图像说明

所以任何人都可以build议我只打一次状态开或关。 或者这是一个错误或什么..?

UPDATE

这里是我的Demo:

编程添加UISwitch

从XIB添加UISwitch

请看下面的代码:

 -(void)viewDidLoad { [super viewDidLoad]; UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(130, 235, 0, 0)]; [mySwitch addTarget:self action:@selector(changeSwitch:) forControlEvents:UIControlEventValueChanged]; [self.view addSubview:mySwitch]; } - (void)changeSwitch:(id)sender{ if([sender isOn]){ NSLog(@"Switch is ON"); } else{ NSLog(@"Switch is OFF"); } } 

这里同样的错误。 我想我已经find了一个简单的解决方法。 我们只需要使用一个新的BOOL来存储UISwitch的前一个状态和一个if语句在我们的IBAction (Value Changed fired)中来检查交换机的值是否已经改变了。

 previousValue = FALSE; [...] -(IBAction)mySwitchIBAction { if(mySwitch.on == previousValue) return; // resetting the new switch value to the flag previousValue = mySwitch.on; } 

没有更奇怪的行为。 希望能帮助到你。

您可以使用UISwitch.selected属性来确保您的代码只在值实际更改时执行一次。 我认为这是一个很好的解决scheme,因为它避免了子类化或添加新的属性。

  //Add action for `ValueChanged` [toggleSwitch addTarget:self action:@selector(switchTwisted:) forControlEvents:UIControlEventValueChanged]; //Handle action - (void)switchTwisted:(UISwitch *)twistedSwitch { if ([twistedSwitch isOn] && (![twistedSwitch isSelected])) { [twistedSwitch setSelected:YES]; //Write code for SwitchON Action } else if ((![twistedSwitch isOn]) && [twistedSwitch isSelected]) { [twistedSwitch setSelected:NO]; //Write code for SwitchOFF Action } } 

这里是在斯威夫特:

 func doToggle(switch: UISwitch) { if switch.on && !switch.selected { switch.selected = true // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE } else { switch.selected = false } } 

如果在应用程序中使用了如此多的开关,那么在定义UISwitch的t action方法的所有地方都有问题。只有在值更改时,才能进行自定义切换和处理事件。

CustomSwitch.h

 #import <UIKit/UIKit.h> @interface Care4TodayCustomSwitch : UISwitch @end 

CustomSwitch.m

 @interface CustomSwitch(){ BOOL previousValue; } @end @implementation CustomSwitch - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code previousValue = self.isOn; } return self; } -(void)awakeFromNib{ [super awakeFromNib]; previousValue = self.isOn; self.exclusiveTouch = YES; } - (void)setOn:(BOOL)on animated:(BOOL)animated{ [super setOn:on animated:animated]; previousValue = on; } -(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ if(previousValue != self.isOn){ for (id targetForEvent in [self allTargets]) { for (id actionForEvent in [self actionsForTarget:targetForEvent forControlEvent:UIControlEventValueChanged]) { [super sendAction:NSSelectorFromString(actionForEvent) to:targetForEvent forEvent:event]; } } previousValue = self.isOn; } } @end 

如果值与更改后的值相同,则忽略事件。在故事板中的所有UISwitch类中都将CustomSwitch置于此位置。这将解决问题并在值更改时仅调用一次

我有很多用户面临同样的问题,所以可能是这个UISwitch bug,所以我刚才发现它的临时解决scheme。 我发现一个gitHub自定义KLSwitch现在使用这个希望苹果将修复此KLSwitch下一个更新: –

https://github.com/KieranLafferty/KLSwitch

如果您不需要立即对交换机的数值做出反应,那么可以采取以下解决scheme:

 - (IBAction)switchChanged:(id)sender { [NSObject cancelPreviousPerformRequestsWithTarget:self]; if ([switch isOn]) { [self performSelector:@selector(enable) withObject:nil afterDelay:2]; } else { [self performSelector:@selector(disable) withObject:nil afterDelay:2]; } } 

我在iOS 9.2中仍然面临同样的问题

我得到了解决scheme,冒充它可能会帮助别人

  1. 跟踪方法调用次数创buildcountvariables

     int switchMethodCallCount = 0; 
  2. 保存开关值的布尔值

     bool isSwitchOn = No; 
  3. 在Switch的值改变方法中,只对第一个方法调用执行欲望行为。 当开关值再次改变设定计数值并且将boolvariables值改变为默认值时

     - (IBAction)frontCameraCaptureSwitchToggle:(id)sender { //This method will be called multiple times if user drags on Switch, //But desire action should be perform only on first call of this method //1. 'switchMethodCallCount' variable is maintain to check number of calles to method, //2. Action is peform for 'switchMethodCallCount = 1' ie first call //3. When switch value change to another state, 'switchMethodCallCount' is reset and desire action perform switchMethodCallCount++ ; //NSLog(@"Count --> %d", switchMethodCallCount); if (switchMethodCallCount == 1) { //NSLog(@"**************Perform Acction******************"); isSwitchOn = frontCameraCaptureSwitch.on [self doStuff]; } else { //NSLog(@"Do not perform"); if (frontCameraCaptureSwitch.on != isSwitchOn) { switchMethodCallCount = 0; isSwitchOn = frontCameraCaptureSwitch.on //NSLog(@"Count again start"); //call value change method again [self frontCameraCaptureSwitchToggle:frontCameraCaptureSwitch]; } } } 

这个问题仍然在iOS 9.3 beta版本中。 如果您不介意用户无法在开关外拖动,我发现使用.TouchUpInside而不是.ValueChanged可以可靠地工作。

当我将交换机连接到其他行为时,这个问题困扰着我。 一般情况下,事情不喜欢从一直到on 。 这是我的简单解决scheme:

 @interface MyView : UIView @parameter (assign) BOOL lastSwitchState; @parameter (strong) IBOutlet UISwitch *mySwitch; @end @implementation MyView // Standard stuff goes here - (void)mySetupMethodThatsCalledWhenever { [self.mySwitch addTarget:self action:@selector(switchToggled:) forControlEvents:UIControlEventValueChanged]; } - (void)switchToggled:(UISwitch *)someSwitch { BOOL newSwitchState = self.mySwitch.on; if (newSwitchState == self.lastSwitchState) { return; } self.lastSwitchState = newSwitchState; // Do your thing } 

每次手动更改mySwitch.on时,还要确保设置mySwitch.on ! 🙂

这种types的问题通常是由ValueChanged引起的。 您不需要按下button来使该function运行。 这不是一个触摸事件。 每次以编程方式将开关切换为开/关,该值都会更改,并再次调用IBAction函数。

@RoNiT有正确的答案:

迅速

 func doToggle(switch: UISwitch) { if switch.on && !switch.selected { switch.selected = true // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE } else { switch.selected = false } }