iOS7 UIS เปลี่ยนค่า EventChanged: การโทรไปเรื่อย ๆ คือ Bug หรืออะไร ..


93

แก้ไข

ตอนนี้ได้รับการแก้ไขแล้ว
อย่าทำการปรับแต่งใด ๆ เพื่อแก้ไข

แก้ไข 2

เห็นได้ชัดว่าปัญหาเดียวกันนี้เกิดขึ้นอีกครั้งใน iOS 8.0 และ 8.1

แก้ไข 3

ตอนนี้ได้รับการแก้ไขแล้ว
อย่าทำการปรับแต่งใด ๆ เพื่อแก้ไข


สวัสดีครับวันนี้ฉันเห็นในUISwitch'sเหตุการณ์ValueChanged:การโทร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 ทำงานได้ดีตามที่เราคาดหวัง:

ป้อนคำอธิบายภาพที่นี่

ใครก็ได้ช่วยแนะนำหน่อยว่าโทรแค่ครั้งเดียวสถานะเปิดหรือปิด หรือนี่คือบั๊กหรืออะไร .. ?

อัปเดต

นี่คือการสาธิตของฉัน:

โปรแกรมเพิ่ม UISwitch

จาก XIB เพิ่ม UISwitch


1
ฉันยังคงได้รับข้อผิดพลาดนี้ใน iOS7.1 บนโปรแกรมจำลองยังไม่ได้ลองใช้อุปกรณ์โดยใช้ xcode 5.1.1
Fonix

3
ฉันพบปัญหาเดียวกันกับ 7.1.2 ipad
Hassy

7
ฉันเห็นปัญหาที่เหมือนกัน / คล้ายกันกับ UISwitch ใน iOS 8.0 และ 8.1
Sea Coast of Tibet

2
ยังคงอยู่ที่นี่ใน 9.1 กรุณาส่งไฟล์openradar.appspot.com/15555929ทุกคนที่ซ้ำกัน นี่เป็นวิธีเดียวที่เราจะแก้ไขได้
Guillaume Algis

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

ขอบคุณสำหรับคำตอบที่ฉันบอกว่าฉันพยายามทั้งสองทางและได้ผลลัพธ์เหมือนกัน atlist ฉันรู้วิธีการเพิ่มโปรแกรม swtich และจาก xib sir
Nitin Gohel

12

ข้อผิดพลาดเดียวกันที่นี่ ฉันคิดว่าฉันพบวิธีแก้ปัญหาง่ายๆแล้ว เราต้องใช้ใหม่BOOLที่เก็บสถานะก่อนหน้าของUISwitchและคำสั่ง if ในIBAction(ค่าเปลี่ยนค่าเริ่มทำงาน) เพื่อตรวจสอบว่าค่าของสวิตช์มีการเปลี่ยนแปลงจริงหรือไม่

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

+1 สิ่งนี้เพราะมันทำให้ฉันใช้วิธีการที่คล้ายกันในการเติมค่า. แท็กเมื่อฉันต้องการละเว้นตรรกะการสลับ ฉันต้องการตรรกะในการเริ่มทำงานในบางครั้งทั้งในโหมดเปิดและปิดดังนั้นข้างต้นจึงไม่เพียงพอ
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 ในสตอรีบอร์ดวิธีนี้จะแก้ไขปัญหาและเรียกเป้าหมายเพียงครั้งเดียวเมื่อค่าเปลี่ยนไป


สิ่งนี้ได้ผลสำหรับฉัน เป็นการดีที่จะไม่ทำให้โค้ดภายนอกถูกเพิ่มด้วยตนเองในไฟล์การนำไปใช้งานของคุณเนื่องจากสามารถใช้ซ้ำได้และซ่อนการใช้งานไว้ในการใช้งานคลาส นี่เป็นเพียงการออกแบบที่ดี คงจะดีถ้าคำตอบนี้มีความคิดเห็นมากกว่านี้เพราะฉันไม่เข้าใจจริงๆว่าทำไมถึงมีโค้ดทั้งหมดอยู่
James 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 เหตุการณ์ติดต่อกัน (state: off, swiping: off, 1st event: on, 2nd event: off) ดังนั้นความล่าช้า 0.1 วินาทีจึงเพียงพอสำหรับฉันและผู้ใช้ไม่สามารถสังเกตเห็นได้
Paul Semionov

3

ปัญหานี้ยังคงอยู่ที่นี่ใน iOS 9.3 เบต้า หากคุณไม่ทราบว่าผู้ใช้ไม่สามารถลากออกจากสวิตช์ได้ฉันพบว่าการใช้งาน.TouchUpInsideแทนที่จะ.ValueChangedทำงานได้อย่างน่าเชื่อถือ


2

ฉันยังคงประสบปัญหาเดียวกันใน iOS 9.2

ฉันมีวิธีแก้ปัญหาและวางตัวเพราะอาจช่วยคนอื่นได้

  1. สร้างตัวแปรการนับเพื่อติดตามจำนวนครั้งที่วิธีการโทร

    int switchMethodCallCount = 0;
    
  2. บันทึกค่าบูลสำหรับค่าสวิตช์

    bool isSwitchOn = No;
    
  3. ในวิธีการเปลี่ยนค่าของ Switch ให้ดำเนินการตามความปรารถนาสำหรับการเรียกวิธีแรกเท่านั้น เมื่อค่าสวิตช์อีกครั้งจะเปลี่ยนค่าการตั้งค่าจำนวนและค่าตัวแปรบูลเป็นค่าเริ่มต้น

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

ปัญหานี้รบกวนฉันเมื่อฉันเปลี่ยนไปใช้พฤติกรรมอื่น โดยทั่วไปสิ่งต่างๆไม่ชอบไปจาก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)
    }

วิธีนี้ใช้งานได้ดีและไม่เรียกใช้ฟังก์ชันตัวเลือกอีก


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.