原有, 写了UIControl的分类, 防止重复点击, 也是在网上copy了很多代码, 之前测试都是跑的Debug版的, 没有任何问题. 上线前跑了个Release版的自测一下, 发现神奇的一幕发生了. 所有UIButton的点击方法只可以实现一次, 不可以跑第二次.
请教了朋友,找了1个多小时, 在朋友的提示下, 问我你是不是有防重. 才想起来分类, 去看了看. 结果果然是这个问题.
第一种解决办法把分类里load方法交换注释掉, 一切ok.
第二种解决办法, 依旧保留方法交换,但是在分类里自定义方法里
// [self performSelector:@selector(setEventUnavailable:) withObject:@(YES) afterDelay:self.emDuration];
修改为
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.emDuration*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.eventUnavailable = NO;
}); 先把问题解决掉了. 后来朋友我们几个就开始讨论为什么会有这种问题. 感谢https://www.coderzhou.com/2017/11/12/%E4%B8%80%E6%AC%A1%E7%94%B1performSelector%E5%BC%95%E5%8F%91%E7%9A%84BUG/ 这个作者的无私奉献. 结合到自己的代码发现是因为Bool值self.eventUnavailable 导致的. performSelector:withObject:afterDelay 这个方法在release和debug下结果不一致
感兴趣的同学可以参考这篇http://blog.zats.io/2014/03/12/performSelector-withObject/ 在32和64环境编译下结果不一样的
另外附上我的垃圾防重点分类. 希望对跟我一样出问题的同学们有帮助. 代码还是自己写吧. 像我就是在网上找的防重点的方法, 网上基本都是这样写的. 出问题了还得自己解决
#import <UIKit/UIKit.h>
@interface UIControl (EMTimer)
// 重复点击间隔
@property (nonatomic, assign) NSTimeInterval emDuration;
@end
实现
#import "UIControl+EMTimerl.h"
#import <objc/runtime.h>
static char * const emDuration = "emDurationKey";
static char * const eventUnavailableKey = "eventUnavailableKey";
@interface UIControl ()
@property (nonatomic, assign) BOOL eventUnavailable;
@end
@implementation UIControl (EMTimer)
+ (void)load {
Method method = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method qi_method = class_getInstanceMethod(self, @selector(qi_sendAction:to:forEvent:));
method_exchangeImplementations(method, qi_method);
}
#pragma mark - Action functions
- (void)qi_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (self.eventUnavailable == NO) {
self.eventUnavailable = YES;
[self qi_sendAction:action to:target forEvent:event];
// [self performSelector:@selector(setEventUnavailable:) withObject:@(YES) afterDelay:self.emDuration];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.emDuration*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.eventUnavailable = NO;
});
}
}
#pragma mark - Setter & Getter functions
- (NSTimeInterval)emDuration {
return [objc_getAssociatedObject(self, emDuration) doubleValue];
}
- (void)setEmDuration:(NSTimeInterval)qi_eventInterval {
objc_setAssociatedObject(self, emDuration, @(qi_eventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)eventUnavailable {
return [objc_getAssociatedObject(self, eventUnavailableKey) boolValue];
}
- (void)setEventUnavailable:(BOOL)eventUnavailable {
objc_setAssociatedObject(self, eventUnavailableKey, @(eventUnavailable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end