iOS7 UISпереключити свою подію ValueChanged: Виклик безперервно це помилка чи що ..?


93

Редагувати

Зараз це зафіксовано
Не робіть жодних налаштувань, щоб виправити це.

Правка2

Мабуть, така ж проблема повторюється в iOS 8.0 та 8.1

Правка3

Зараз це зафіксовано
Не робіть жодних налаштувань, щоб виправити це.


Привіт Сьогодні я бачив у UISwitch'sEvent ValueChanged:Calling, continuously коли я переходжу Onна Offабо Offна On, і мій палець перемістився як на правий, так і на лівий бік. Я відвідував GIF-зображення для більш чіткого використання з NSLog.

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

Мій метод, який змінив значення:

- (IBAction)changeSwitch:(id)sender{

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

iOS6 той самий код Switch Switch Fine, як ми очікували:

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

тому хтось може запропонувати мені зателефонувати лише один раз, коли його стан увімкнено чи вимкнено. або це помилка чи що ..?

ОНОВЛЕННЯ

Ось моя демонстрація цього:

програмно Додати UISwitch

від XIB додаючи UISwitch


1
я все ще отримую цю помилку в iOS7.1 на тренажері, ще не пробував пристрій, працює xcode 5.1.1
Fonix

3
У мене
виникають ті

7
Я можу побачити ідентичну / подібну проблему з UISwitch в iOS 8.0 і 8.1
Sea Coast of Tibet

2
Ще тут у 9.1. Будь ласка, подайте дублікат openradar.appspot.com/15555929 кожному. Це єдиний спосіб вирішити це.
Гійом Алгіс

1
Здається, це повернеться в 9.3
Бен Леджіеро

Відповіді:


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 Я знаю, як додати swtich програмно, а також від Xib сер.
Нітін Гогель

12

Тут же помилка. Я думаю, що я знайшов просте вирішення. Нам просто потрібно використати нове, BOOLщо зберігає попередній стан UISwitchоператора і if, якщо в нашому IBAction(Value Changed запускається) перевірити, чи змінено значення перемикача.

previousValue = FALSE;

[...]

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

Більше дивного поведінки немає. Сподіваюся, це допомагає.


2
це просто слід сказати, якщо (mySwitch.on == попереднійValue)
Кіган Джей

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

І ось воно в Свіфті:

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

6
Я вважаю це найпростішим.
zekel

+1 це позначило це, оскільки це призвело до використання аналогічного рішення заповнення значення .tag, коли я хочу ігнорувати логіку перемикання. Мені потрібна логіка для запуску в режимі ввімкнення та вимкнення, тому вищезазначене було недостатньо.
davidethell

9

Якщо у вашій програмі використовується стільки комутаторів, то існує проблема змінити код у всіх місцях, де визначений метод дії 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 на раскадровці. Це вирішить проблему та націлюватиме виклик лише один раз, коли значення зміниться


Це працювало для мене. Ідеально тим, що він не спричиняє вручну додавати сторонні коди у ваші файли реалізації, оскільки він багаторазовий і приховує його реалізацію всередині класової реалізації. Це просто хороший дизайн. Було б добре, якби ця відповідь мала більше коментарів, тому що я не дуже розумію, чому весь код є.
Джеймс C

Дякую, у мене це вийшло. Чи можете ви пояснити код трохи більше. @codester
Swayambhu

7

У мене багато користувачів, які стикаються з тією ж проблемою, тому, можливо, це помилка, UISwitchтому я знайшов саме зараз тимчасове рішення її. Я знайшов один gitHubкористувальницький спосіб KLSwitchвикористання цього на даний момент, сподіваюся, що Apple виправить це в наступному оновлення 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 події поспіль (стан: вимкнено, розмикання: вимкнено, 1-я подія: увімкнено, 2-я подія: вимкнено), тому затримка на 0,1 секунди мені достатня і не помітна користувачеві.
Павло Семіонов

3

Ця проблема як і раніше для iOS 9.3 beta. Якщо ви не заперечуєте проти того, щоб користувач не зміг перетягнути його за межі комутатора, я вважаю, що використання, .TouchUpInsideа не .ValueChangedнадійність, працює.


2

Я все ще стикаюся з тією ж проблемою в iOS 9.2

Я отримав рішення та позував, як це може допомогти іншим

  1. Створіть змінну підрахунку, щоб відстежити кількість разів, за допомогою якої виклик

    int switchMethodCallCount = 0;
  2. Збережіть значення bool для значення перемикача

    bool isSwitchOn = No;
  3. У методі зміни значення перемикача виконують бажання лише для виклику першого методу. Коли значення перемикання знову змінюється встановлене значення count і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. Я реалізував вашу логіку, і зараз вона працює так, як я задумав.
Нік Корн

2

Ця проблема мене мучить, коли я перемикаю перехід на іншу поведінку. Взагалі - то не подобається , щоб перейти від 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! :)


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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.