iOS7 UIS Alihkan Nilai Peristiwa Berubah: Menelepon terus menerus apakah Bug ini atau apa ..?

93

Edit

Sekarang sudah diperbaiki
Jangan lakukan tweak apapun untuk memperbaikinya.

Edit2

Ternyata masalah yang sama terjadi lagi di iOS 8.0 dan 8.1

Edit3

Sekarang sudah diperbaiki
Jangan lakukan tweak apapun untuk memperbaikinya.


Hai Hari ini saya melihat di UISwitch'sEvent ValueChanged:Calling continuously saat saya mengubah Onke Offatau Offke On dan jari saya masih digerakkan di sisi kanan dan kiri. Saya menggunakan gambar GIF agar lebih jelas dengan NSLog.

masukkan deskripsi gambar di sini

Metode Perubahan Nilai Saya adalah:

- (IBAction)changeSwitch:(id)sender{

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

iOS6 kode yang sama dari Switch berfungsi dengan baik seperti yang kami harapkan:

masukkan deskripsi gambar di sini

jadi siapa pun bisa menyarankan saya panggilan itu hanya satu kali keadaannya Hidup atau mati. atau apakah ini bug atau apa ..?

MEMPERBARUI

Ini dia Demo saya:

Tambahkan UISwitch terprogram

dari XIB menambahkan UISwitch

Nitin Gohel
sumber
1
Saya masih mendapatkan bug ini di iOS7.1 pada simulator, belum mencoba perangkat, menjalankan xcode 5.1.1
Fonix
3
Saya mendapatkan masalah yang sama dengan 7.1.2 ipad
Hassy
7
Saya dapat melihat masalah yang identik / serupa dengan UISwitch di iOS 8.0 dan 8.1
Pesisir Laut Tibet
2
Masih di sini di 9.1. Silakan ajukan duplikat openradar.appspot.com/15555929 semuanya. Ini adalah satu-satunya cara kita memperbaikinya.
Guillaume Algis
1
Tampaknya itu kembali pada 9,3
Ben Leggiero

Jawaban:

44

Silakan lihat kode berikut:

-(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");
    }
}
AeroStar
sumber
terima kasih untuk jawaban seperti yang saya katakan saya mencoba kedua cara dan mendapatkan hasil yang sama. atlist saya tahu cara menambahkan programmatic swtich serta dari xib pak.
Nitin Gohel
12

Bug yang sama di sini. Saya rasa saya telah menemukan solusi sederhana. Kita hanya perlu menggunakan new BOOLyang menyimpan status sebelumnya dari UISwitchdan pernyataan if di IBAction(Value Changed dipecat) untuk memeriksa bahwa nilai switch benar-benar berubah.

previousValue = FALSE;

[...]

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

Tidak ada lagi perilaku aneh. Semoga membantu.

nnarayann
sumber
2
ini seharusnya hanya mengatakan jika (mySwitch.on == nilai sebelumnya)
Keegan Jay
12

Anda dapat menggunakan UISwitch's .selectedproperti untuk memastikan kode Anda hanya mengeksekusi sekali ketika nilai perubahan yang sebenarnya. Saya rasa ini adalah solusi yang bagus karena menghindari subclass atau menambahkan properti baru.

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

Dan ini dia di Swift:

func doToggle(switch: UISwitch) {
    if switch.on && !switch.selected {
        switch.selected = true
        // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE
    } else {
        switch.selected = false
    }
}
itsji10dra
sumber
6
Menurut saya yang ini paling sederhana.
zekel
Memberi ini +1 karena itu membuat saya menggunakan solusi serupa untuk mengisi nilai .tag ketika saya ingin mengabaikan logika toggle. Saya memerlukan logika untuk mengaktifkan kadang-kadang dalam mode hidup dan mati sehingga hal di atas tidak cukup memadai.
davidethell
9

Jika Anda menggunakan begitu banyak sakelar di aplikasi Anda, maka ada masalah untuk mengubah kode di semua tempat di mana metode t tindakan UISwitch didefinisikan. Anda dapat membuat sakelar khusus dan menangani kejadian hanya jika nilainya berubah.

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

Kami mengabaikan peristiwa jika nilainya sama dengan nilai yang diubah.Tempatkan CustomSwitch di semua kelas UISwitch di storyboard Ini akan menyelesaikan masalah dan memanggil target hanya sekali ketika nilai berubah

pembuat kode
sumber
Ini berhasil untuk saya. Ini ideal karena tidak menyebabkan kode asing ditambahkan secara manual ke dalam file implementasi Anda, karena dapat digunakan kembali dan menyembunyikan implementasinya di dalam implementasi kelas. Ini desain yang bagus. Alangkah baiknya jika jawaban ini memiliki lebih banyak komentar, karena saya tidak begitu mengerti mengapa semua kode ada di sana.
James C
Terima kasih, itu berhasil untuk saya. Bisakah Anda menjelaskan kodenya sedikit lebih banyak. @codester
Swayambhu
7

Saya mendapat banyak pengguna yang menghadapi masalah yang sama jadi mungkin ini adalah bug UISwitchjadi saya baru saja menemukan untuk solusi sementara. Saya menemukan satu penggunaan gitHubkhusus KLSwitchini untuk saat ini berharap apel akan memperbaikinya di pembaruan xCode berikutnya: -

https://github.com/KieranLafferty/KLSwitch

Nitin Gohel
sumber
6

Jika Anda tidak perlu bereaksi secara instan terhadap perubahan nilai sakelar, berikut ini bisa menjadi solusi:

- (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];
  }
}
pra
sumber
Bekerja seperti pesona di iOS 11.2. Dalam situasi saya, itu menembakkan 2 kejadian berturut-turut (status: mati, gesek: mati, kejadian pertama: hidup, kejadian kedua: mati), jadi penundaan 0,1 detik sudah cukup bagi saya dan tidak terlihat oleh pengguna.
Paul Semionov
3

Masalah ini masih ada di iOS 9.3 beta. Jika Anda tidak keberatan pengguna tidak dapat menyeret di luar sakelar, saya menemukan bahwa menggunakan .TouchUpInsidedaripada .ValueChangedbekerja dengan andal.

Nick Kohrn
sumber
2

Saya masih menghadapi masalah yang sama di iOS 9.2

Saya mendapat solusi dan berpura-pura karena dapat membantu orang lain

  1. Buat variabel hitung untuk melacak berapa kali metode mendapat panggilan

    int switchMethodCallCount = 0;
  2. Simpan nilai bool untuk nilai sakelar

    bool isSwitchOn = No;
  3. Dalam metode perubahan nilai Switch lakukan tindakan keinginan hanya untuk pemanggilan metode pertama. Ketika nilai sakelar berubah lagi setel nilai hitungan dan nilai variabel bool ke default

    - (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];
    
    
        }
    }
    
    
    }
Chetan Koli
sumber
Saya, juga, masih menghadapi masalah ini di 9.2. Saya menerapkan logika Anda, dan sekarang berfungsi seperti yang saya inginkan.
Nick Kohrn
2

Masalah ini mengganggu saya ketika saya mengikat peralihan ke perilaku lain. Umumnya hal-hal tidak suka berubah dari onmenjadi on. Inilah solusi sederhana saya:

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

Pastikan juga untuk mengatur self.lastSwitchStatesetiap kali Anda mengubah secara manual mySwitch.on! :)

Ben Leggiero
sumber
1

Jenis masalah ini sering kali disebabkan oleh ValueChanged. Anda tidak perlu menekan tombol untuk menjalankan fungsi. Ini bukan acara sentuh. Setiap kali Anda secara terprogram mengubah sakelar ke on / off, nilainya berubah dan memanggil fungsi IBAction lagi.

@RoNiT memiliki jawaban yang benar dengan:

Cepat

func doToggle(switch: UISwitch) {
    if switch.on && !switch.selected {
        switch.selected = true
        // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE
    } else {
        switch.selected = false
    }
}
Dave G
sumber
0
DispatchQueue.main.async {
        self.mySwitch.setOn(false, animated: true)
    }

Ini berfungsi dengan baik dan tidak memanggil fungsi pemilih lagi.

anuraagdjain
sumber
0

Ini berhasil untuk saya.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()){
    self.switch.isOn = true
}
pengguna3305074
sumber