IOS

UISwitch的那些坑

2017-08-16  本文已影响518人  ibingewin

主要就是基于事件UIControlEventValueChanged的回调问题

坑1:事件频繁触发

触发条件:拖动UISwitch控件,划出控件区域,直至改变状态后,持续拖动不松手,事件仍会不断的触发,如下所示:

PPCamara_20170816150214.gif

如果回调里处理的是网络相关的业务,这样会导致不断地进行网络请求,无端的浪费服务器资源。

ps:具体哪个版本存在这个问题,我不确定,猜测是iOS 10.0之前,上图使用iOS 9.3.5

解决方法

@property (nonatomic, strong)NSNumber *lb_on;

- (void)switchAction:(UISwitch *)sender {
    if (self.lb_on && self.lb_on.boolValue == sender.isOn) return;
    self.lb_on = @(sender.isOn);
    [self doSomething];
}
@interface UIControl (Extension)
@property (nonatomic, copy)NSNumber *lb_on;
@end
@implementation UIControl (Extension)
- (NSNumber *)lb_on {
    return objc_getAssociatedObject(self, @selector(lb_on));
}
- (void)setLb_on:(NSNumber *)lb_on {
    objc_setAssociatedObject(self, @selector(lb_on), lb_on, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        method_exchangeImplementations(class_getInstanceMethod(self, @selector(sendAction:to:forEvent:)), class_getInstanceMethod(self, @selector(lb_sendAction:to:forEvent:)));
    });
}
- (void)lb_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    if ([self isKindOfClass:[UISwitch class]]) {
        UISwitch *sw = (UISwitch *)self;
        if (sw.lb_on && sw.lb_on.boolValue == sw.isOn) return;
        
        sw.lb_on = @(sw.isOn);
        [self lb_sendAction:action to:target forEvent:event];
    }
}

@end

坑2:事件重复触发

新版本的SDK解决了上一个坑,但是又带出了这一个坑,我一直以为事件都是用户交互产生的,UISwitchon属性,只是用来设置其的开关UI状态的,没想到还能触发事件,简直颠覆我的认知!

- (void)switchAction:(UISwitch *)sender {
    self.sw.on = !self.sw.isOn;
    LBLog(@"switch is %@", self.sw.isOn ? @"on" : @"off");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"touch began");
    self.sw.on = !self.sw.isOn;
}

效果如下:在事件回调之外,设置on,表现都是如期的,可是如果在事件回调内设置on,居然又触发了一次事件,WTF!!!

PPCamara_20170816161205.gif

如果事件中是网络相关业务,当当前没网,或者请求失败时,还需要还原UISwitch的状态,即设置UISwitchon属性,但悲剧的是,当还原状态时,又触发了一次事件,再对还原后的状态还原,负负得正,结果是并没有还原,导致出现Bug

ps:同上个坑一样,我也不确定具体哪个版本存在这个问题,应该是解决了上个bug,才带出这个bug的,猜测是iOS 10.0之后,上图是iOS 10.3.3

解决办法

@property (nonatomic, assign)BOOL setOnInEvent;

- (void)switchAction:(UISwitch *)sender {
    __weak typeof(self) weakSelf = self;
    if ([UIDevice currentDevice].systemVersion.floatValue >= 10.0) {
        if (self.onInEvent) {
            self.onInEvent = NO;
            return;
        }
        [self doNetworkFailure:^{
            weakSelf.onInEvent = YES;
            weakSelf.sw.on = !weakSelf.sw.isOn;
        }];
    }else {
        [self doNetworkFailure:^{
            weakSelf.sw.on = !weakSelf.sw.isOn;
        }];
    }
}
- (void)switchAction:(UISwitch *)sender {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.sw.on = !self.sw.isOn;
    });
}
上一篇 下一篇

猜你喜欢

热点阅读