iOS7 UISwitch 이벤트 ValueChanged : 지속적으로 호출하는 것은이 버그 또는 무엇입니까 ..?


93

편집하다

이제 수정되었습니다.
그것을 고치기 위해 어떤 조정도하지 마십시오.

편집 2

분명히 동일한 문제가 iOS 8.0 및 8.1에서 다시 발생합니다.

편집 3

이제 수정되었습니다.
그것을 고치기 위해 어떤 조정도하지 마십시오.


안녕하세요 오늘은 내가 볼 UISwitch's이벤트 ValueChanged:를 호출 continuously 난에 변화를 생각하면서 On까지 Off또는 OffOn으로 내 손가락을 왼쪽뿐만 아니라 오른쪽에 여전히 움직였다. NSLog로 더 명확하게 GIF 이미지를 만들었습니다.

여기에 이미지 설명 입력

내 가치 변경 방법은 다음과 같습니다.

- (IBAction)changeSwitch:(id)sender{

    if([sender isOn]){
        NSLog(@"Switch is ON");
    } else{
        NSLog(@"Switch is OFF");
    }
    
}

iOS6 스위치의 동일한 코드가 예상대로 잘 작동합니다.

여기에 이미지 설명 입력

그래서 누구든지 그 상태를 On 또는 Off로 한 번만 호출하도록 제안 할 수 있습니다. 아니면이게 벌레 야 ..?

최신 정보

여기 내 데모가 있습니다.

프로그래밍 방식 추가 UISwitch

XIB에서 UISwitch 추가


1
im은 여전히 ​​시뮬레이터의 iOS7.1에서이 버그를 받고 있으며, 아직 장치를 시도하지 않았으며 xcode 5.1.1을 실행합니다
Fonix

3
7.1.2 ipad에서도 같은 문제가 발생합니다
Hassy 2014-07-07

7
iOS 8.0 및 8.1의 UISwitch에서 동일 / 유사한 문제를 볼 수 있습니다
Sea Coast of Tibet

2
9.1에서 여전히 여기 있습니다. openradar.appspot.com/15555929 모두 의 사본을 제출하십시오 . 이것이 우리가 이것을 고칠 수있는 유일한 방법입니다.
Guillaume Algis 2015 년

1
9.3에서 돌아온 것 같습니다
Ben Leggiero

답변:


44

다음 코드를 참조하십시오.

-(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");
    }
}

내가 두 가지 방법을 시도하고 같은 결과를 얻었다 고 말했듯이 대답을 위해 thx. atlist 나는 xib 선생님뿐만 아니라 프로그래밍 방식으로 swtich를 추가하는 방법을 알고 있습니다.
Nitin Gohel 2013 년

12

여기에도 같은 버그가 있습니다. 간단한 해결 방법을 찾은 것 같습니다. 스위치의 값이 실제로 변경되었는지 확인하기 위해 (Value Changed fired)에 if 문과 BOOL의 이전 상태를 저장 하는 new를 사용해야합니다 .UISwitchIBAction

previousValue = FALSE;

[...]

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

더 이상 이상한 행동이 없습니다. 도움이되기를 바랍니다.


2
if (mySwitch.on == previousValue)
Keegan Jay

12

UISwitch.selected속성을 사용하여 실제 값이 변경 될 때 코드가 한 번만 실행되도록 할 수 있습니다 . 하위 클래스를 만들거나 새 속성을 추가 할 필요가 없기 때문에 이것이 훌륭한 솔루션이라고 생각합니다.

 //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
    }
}

그리고 여기 Swift에 있습니다.

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

6
나는 이것이 가장 간단하다고 생각합니다.
zekel

토글 로직을 무시하고 싶을 때 .tag 값을 채우는 비슷한 솔루션을 사용하게 되었기 때문에 +1했습니다. 가끔 켜짐과 꺼짐 모드 모두에서 발생하는 논리가 필요하므로 위의 내용은 충분하지 않습니다.
davidethell

9

앱에서 너무 많은 스위치를 사용하는 경우 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를 넣으면 문제가 해결되고 값이 변경된 경우 대상을 한 번만 호출합니다.


이것은 나를 위해 일했습니다. 재사용이 가능하고 클래스 구현 내부에 구현을 숨길 수 있으므로 구현 파일에 불필요한 코드를 수동으로 추가하지 않는 것이 이상적입니다. 이것은 좋은 디자인입니다. 이 답변에 더 많은 주석이 있으면 좋을 것입니다. 왜 모든 코드가 있는지 이해하지 못하기 때문입니다.
James C

고마워요. 코드에 대해 좀 더 설명해 주시겠습니까? @codester
Swayambhu

7

나는 같은 문제에 직면 한 많은 사용자가 있으므로 이것이 버그 일 수 UISwitch있으므로 일시적인 해결책을 찾았습니다. 나는 지금 이것을 사용하는 하나의 gitHub사용자 정의를 찾았습니다 KLSwitch. xCode의 다음 업데이트에서 사과가 이것을 고칠 것입니다.

https://github.com/KieranLafferty/KLSwitch


6

스위치의 값 변경에 즉시 반응 할 필요가 없다면 다음이 해결책이 될 수 있습니다.

- (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 11.2에서 매력처럼 작동했습니다. 내 상황에서는 연속으로 2 개의 이벤트 (상태 : 꺼짐, 스 와이프 : 꺼짐, 첫 번째 이벤트 : 켜짐, 두 번째 이벤트 : 꺼짐)가 발생했기 때문에 0.1 초의 지연이 충분하며 사용자에게는 눈에 띄지 않습니다.
Paul Semionov 2017

3

이 문제는 iOS 9.3 베타에서 여전히 여기에 있습니다. 사용자가 스위치 외부로 드래그 할 수 없다는 점에 신경 쓰지 않는다면 안정적으로 작동 하는 .TouchUpInside대신 사용 하는 것을 알 .ValueChanged수 있습니다.


2

iOS 9.2에서 여전히 동일한 문제에 직면하고 있습니다.

나는 해결책을 얻었고 다른 사람들에게 도움이 될만한 포즈를 취했습니다.

  1. 메서드가 호출 된 횟수를 추적하기 위해 카운트 변수를 만듭니다.

    int switchMethodCallCount = 0;
  2. 스위치 값에 대한 부울 값 저장

    bool isSwitchOn = No;
  3. Switch의 값 변경 방식에서는 첫 번째 메서드 호출에 대해서만 원하는 동작을 수행합니다. 스위치 값이 다시 변경되면 설정된 카운트 값 및 t bool 변수 값이 기본값으로

    - (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' i.e 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];
    
    
        }
    }
    
    
    }

나도 9.2에서 여전히이 문제에 직면하고 있습니다. 나는 당신의 논리를 구현했으며 이제 의도 한대로 작동합니다.
Nick Kohrn

2

이 문제는 내가 스위치를 다른 행동에 묶을 때 나를 괴롭힌다. 일반적으로 가지에서 가고 싶어하지 않습니다 onon. 내 간단한 해결책은 다음과 같습니다.

@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
}

self.lastSwitchState수동으로 변경할 때마다 설정하십시오 mySwitch.on! :)


1

이러한 유형의 문제는 종종 ValueChanged로 인해 발생합니다. 기능을 실행하기 위해 버튼을 누를 필요가 없습니다. 터치 이벤트가 아닙니다. 프로그래밍 방식으로 스위치를 켜기 / 끄기로 변경할 때마다 값이 변경되고 IBAction 함수를 다시 호출합니다.

@RoNiT는 다음과 같이 정답을 얻었습니다.

빠른

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

0
DispatchQueue.main.async {
        self.mySwitch.setOn(false, animated: true)
    }

이것은 잘 작동하며 선택기 함수를 다시 호출하지 않습니다.


0

이것은 나를 위해 일했습니다.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()){
    self.switch.isOn = true
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.