错误
app 在线上有个崩溃的问题, crash原因为-[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instance.
原因分析
然后发现是在手写输入的时候会crash,每当提示文字的区域就会crash。这个崩溃是由在UIScrollview的category中重写的三个方法引起的, 代码如下:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
[self.nextResponder touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[self.nextResponder touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
[self.nextResponder touchesCancelled:touches withEvent:event];
}
具体原因是由于提示文字区域(Candidate View)点击时, 同样执行上面的代码, 然后事件响应向上传递, 直到出现标题的错误。
再具体些, 就是手写的键盘的提示文字的区域是UIKBCandidateCollectionView
类(其父类是UIColloectionView
)的实例,这个view的nextResponder是UIKBHandwritingCandidateView
类的实例。执行UIKBHandwritingCandidateView
的touchesBegan:withEvent:方法后,会使得整个candidate view呈选中状态,而苹果对于手写键盘的提示文字区域, 会避免candidate view呈选中状态的。整个candidate view呈选中状态后再点击键盘的任意地方,本应调用UIKBCandidateView
实例的方法candidateList,结果调用了UIKBBlurredKeyView
的candidateList方法,导致方法找不到,导致”-[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instance “crash。
解决方案
方案一
摒弃此代码, 选择其他方式代替。
方案二
对于不同的类, 对其进行类型判断, 加强代码的健壮性, 以避免崩溃。比如, UIScrollView
中要加入下判断:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if([self isMemberOfClass:[UIScrollView class]]) {
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
}
方案三
使用UITapGestureRecognizer
类, 进行用户的点击事件拦截, 且要将tap的cancelsTouchesInView
属性设置为NO
, 否则会屏蔽到当前View的点击事件。下面以UIScrollView
和’UITableView’为例的处理方案:
1.在UIScrollView上面加一个UIView, 通过在view上面的手势来改变键盘
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];
tap.cancelsTouchesInView = NO;
[backView addGestureRecognizer:tap];
2.在UITableView上改变键盘
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];
tap.cancelsTouchesInView = NO;
[tableView addGestureRecognizer:tap];