iOS7 UISwitch его значение событияChanged: непрерывный вызов - это ошибка или что ..?

Редактировать

Теперь это исправлено на ios7.1
Не делайте никаких настроек, чтобы исправить это.

Редактировать2

По-видимому, та же проблема снова возникает в iOS 8.0 и 8.1.

Редактировать3

Теперь это исправлено на ios9.2
Не делайте никаких настроек, чтобы исправить это.


Привет Сегодня я видел в UISwitch's Событии ValueChanged: Вызов continuously, когда я меняю On на Off или Off на Вкл, и мой палец все еще двигался как с правой, так и с левой стороны. Я прикрепил изображение GIF для большей ясности с NSLog.

введите здесь описание изображения

Мой метод изменения значения:

- (IBAction)changeSwitch:(id)sender{

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

iOS6 тот же код Switch работает нормально, как мы и ожидали:

введите здесь описание изображения

так может ли кто-нибудь предложить мне этот вызов только один раз, когда его состояние включено или выключено. или это баг или что..?

ОБНОВЛЕНИЕ

Вот моя демонстрация этого:

программное добавление UISwitch

из XIB с добавлением UISwitch


person Nitin Gohel    schedule 28.10.2013    source источник
comment
Вы пытались перезапустить xCode?   -  person D-eptdeveloper    schedule 28.10.2013
comment
это не в моем xcode, эта проблема в моем xcode, а также в xcode моего frnd   -  person Nitin Gohel    schedule 28.10.2013
comment
Я. У меня тоже такая же проблема, когда я пытался здесь.. Это может быть ошибка..   -  person Bala    schedule 28.10.2013
comment
у меня такая же проблема..   -  person Jageen    schedule 28.10.2013
comment
привет @NitinGohel, у меня все работает нормально ..   -  person Rajneesh071    schedule 28.10.2013
comment
у меня точно такая же проблема, и я собираюсь изменить UISwitch на обычную кнопку. Ваше здоровье!   -  person Joey    schedule 28.11.2013
comment
Это ошибка в элементе управления uiswitch вместо добавления дополнительного пользовательского компонента, я применил ответ nnarayann и предварительный ответ вместе, и это решает мою проблему.   -  person Saeed    schedule 02.02.2014
comment
Не нужно ничего делать... Это исправлено на iOS7.1.   -  person Inder Kumar Rathore    schedule 12.04.2014
comment
я все еще получаю эту ошибку в iOS7.1 на симуляторе, еще не пробовал устройство, работая с xcode 5.1.1   -  person Fonix    schedule 13.05.2014
comment
У меня такая же проблема с 7.1.2 ipad   -  person Hassy    schedule 07.07.2014
comment
Я вижу идентичную/похожую проблему с UISwitch в iOS 8.0 и 8.1.   -  person Sea Coast of Tibet    schedule 23.10.2014
comment
У меня тоже самое с 8.1   -  person Dsw    schedule 21.05.2015
comment
Еще здесь, в 9.1. Отправьте дубликат openradar.appspot.com/15555929 всем. Это единственный способ исправить это.   -  person Guillaume Algis    schedule 29.10.2015
comment
Столкнувшись с этой проблемой в 9.1 на устройстве, я обнаружил, что иногда событие ValueChanged вообще не генерируется и метод не вызывается.   -  person ghr    schedule 15.12.2015
comment
Кажется, он вернулся в 9.3   -  person Ky Leggiero    schedule 22.04.2016


Ответы (12)


См. следующий код:

-(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");
    }
}
person AeroStar    schedule 28.10.2013
comment
спасибо за ответ, как я уже сказал, я пытался в обоих направлениях и получил тот же результат. atlist, я знаю, как добавить swtich программно, а также из xib, сэр. - person Nitin Gohel; 28.10.2013

Здесь та же ошибка. Кажется, я нашел простой обходной путь. Нам просто нужно использовать новый BOOL, в котором хранится предыдущее состояние UISwitch, и оператор if в нашем IBAction (значение изменено), чтобы проверить, действительно ли значение переключателя изменилось.

previousValue = FALSE;

[...]

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

Больше никакого странного поведения. Надеюсь, поможет.

person nnarayann    schedule 17.01.2014
comment
это должно просто сказать, если (mySwitch.on == предыдущее значение) - person Keegan Jay; 06.02.2014

Вы можете использовать свойство .selected UISwitch, чтобы убедиться, что ваш код выполняется только один раз, когда фактическое значение изменяется. Я думаю, что это отличное решение, потому что оно позволяет избежать создания подклассов или добавления новых свойств.

 //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
    }
}
person itsji10dra    schedule 06.11.2015
comment
Я считаю, что это самое простое. - person zekel; 11.02.2016
comment
+1, потому что это привело меня к использованию аналогичного решения для заполнения значения .tag, когда я хочу игнорировать логику переключения. Мне нужно, чтобы логика иногда срабатывала как во включенном, так и в выключенном режиме, поэтому вышеизложенного было недостаточно. - person davidethell; 24.03.2017

Если вы используете так много переключателей в своем приложении, возникает проблема с изменением кода во всех местах, где определен метод действия UISwitch. Вы можете сделать собственный переключатель и обрабатывать события только при изменении значения.

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

Мы игнорируем события, если значение совпадает с измененным значением. Поместите CustomSwitch во все классы UISwitch в раскадровке. Это решит проблему и вызовет цель только один раз при изменении значения.

person codester    schedule 23.03.2014
comment
Это сработало для меня. Он идеален тем, что не требует ручного добавления постороннего кода в ваши файлы реализации, поскольку его можно использовать повторно, и он скрывает свою реализацию внутри реализации класса. Это просто хороший дизайн. Было бы неплохо, если бы в этом ответе было больше комментариев, потому что я действительно не понимаю, зачем там весь код. - person James C; 22.04.2015
comment
Спасибо, это сработало для меня. Можете ли вы объяснить код немного больше. @кодестер - person Swayambhu; 17.12.2015

У меня есть много пользователей, которые сталкиваются с одной и той же проблемой, так что может быть это ошибка UISwitch, поэтому я только что нашел временное решение. Я нашел один gitHub пользовательский KLSwitch, используйте его сейчас, надеюсь, что Apple исправит это в следующем обновлении xCode: -

https://github.com/KieranLafferty/KLSwitch

person Nitin Gohel    schedule 28.10.2013

Если вам не нужно мгновенно реагировать на изменение значения переключателя, решением может быть следующее:

- (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];
  }
}
person pre    schedule 20.11.2013
comment
Работал как шарм в iOS 11.2. В моей ситуации он запускал 2 события подряд (состояние: выкл., смахивание: выкл., 1-е событие: вкл., 2-е событие: выкл.), поэтому задержки в 0,1 с для меня достаточно и незаметно для пользователя. - person Paul Semionov; 13.12.2017

Эта проблема все еще здесь, начиная с бета-версии iOS 9.3. Если вы не возражаете, что пользователь не может перетаскивать за пределы переключателя, я считаю, что использование .TouchUpInside вместо .ValueChanged работает надежно.

person Nick Kohrn    schedule 19.02.2016

Я все еще сталкиваюсь с той же проблемой в iOS 9.2.

У меня есть решение, и я притворяюсь, что это может помочь другим

  1. Создайте переменную count, чтобы отслеживать, сколько раз метод получил вызов

    int switchMethodCallCount = 0;
    
  2. Сохранить логическое значение для значения переключателя

    bool isSwitchOn = No;
    
  3. В методе изменения значения Switch выполните желаемое действие только для первого вызова метода. Когда значение переключателя снова изменится, установите значение счетчика и значение переменной 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];
    
    
        }
    }
    
    
    }
    
person Chetan Koli    schedule 19.01.2016
comment
Я тоже все еще сталкиваюсь с этой проблемой в 9.2. Я реализовал вашу логику, и теперь она работает так, как я задумал. - person Nick Kohrn; 02.02.2016

Эта проблема мучает меня, когда я привязываю переключатель к другому поведению. Обычно вещи не любят переходить от on к on. Вот мое простое решение:

@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! :)

person Ky Leggiero    schedule 21.04.2016

Этот тип проблемы часто вызывается 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
    }
}
person Dave G    schedule 14.01.2017

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

Это отлично работает и больше не вызывает функцию селектора.

person anuraagdjain    schedule 15.05.2018

Это сработало для меня.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()){
    self.switch.isOn = true
}
person user3305074    schedule 04.03.2019