中文手写输入法闪退问题

近日有用户报 app 调用中文手写输入法时出现闪退。问题描述可以参照网上:

笔者的这个 App 中也是一样,使用了 +UITouch 分类重写了 ScrollView 的 touchesXXX 方法。
网上提到的解决办法都是千篇一律,即不要重写 ScrollView 的 touchesXXX 方法。但这个 app 中这是不可能的,因为笔者有一个自定义控件必须要让 scrollView 响应点击事件。

经过调试发现,这个崩溃是因为中文输入法中一个私有类 UIKBCandidateCollectionView(即显示候选词条的 bar)也是一个 UIScrollView ):

(lldb) cpo self
<UIKBCandidateCollectionView: 0x1040b5c00; frame = (0 0; 369 38); clipsToBounds = YES; opaque = NO; autoresize = LM+H; gestureRecognizers = <NSArray: 0x17424b4c0>; layer = <CALayer: 0x170225ac0>; contentOffset: {0, 0}; contentSize: {1003, 38}> collection view layout: <UICollectionViewFlowLayout: 0x103d4f090>

(lldb) cpo [self superclass]
UICollectionView

(lldb) cpo [[self superclass] superclass]
UIScrollView

而这个类的 nextResponder 是一个 UIKBHandwritingCandidateView:

(lldb) cpo [self nextResponder]
<UIKBHandwritingCandidateView: 0x10032ef90; frame = (0 0; 369 38); opaque = NO; layer = <CALayer: 0x170236dc0>>

而当 UIKBCandidateCollectionView 调用 nextResponder 的 touchesBegan:withEvent: 方法时就会 crash。

具体机制未细究,估计是 iOS 的 bug(有时间提给苹果吧)。于是解决办法就是修改 +UITouch 分类,在向 nextResponder 传递触摸事件之前做一个判断,发现是 UIKBCandidateCollectionView 类就不传递触摸事件:

#import "UIScrollView+UITouch.h"
#import <objc/runtime.h>

@implementation UIScrollView(UITouch)

-(NSString* )getClassName{
    return NSStringFromClass([self class]);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if(![[self getClassName] hasPrefix:@"UIKB"]){
        [[self nextResponder] touchesBegan:touches withEvent:event];
    }
    [super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if(![[self getClassName] hasPrefix:@"UIKB"]){
        [[self nextResponder] touchesMoved:touches withEvent:event];
    }
    [super touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if(![[self getClassName] hasPrefix:@"UIKB"]){
        [[self nextResponder] touchesEnded:touches withEvent:event];
    }
    [super touchesEnded:touches withEvent:event];
}


@end

注意:Category 分类哪怕是不用导入头文件也会自动失效,这和普通类不一样(普通的类不导入头文件是不会加载的)。只不过如果你不导入分类的头文件的话,你无法在源代码中调用其扩展和覆盖的方法。但 +UITouch 这个分类不同,它的所有 touchesXXX 方法是触摸发生时自动调用的,不需要你在源代码中手动调用。

其实我们可以有另一种更好的选择,即继承 UIScrollView 子类,然后在子类中覆盖 touchesXXX 方法,从而避免在 Category 中使用私有 API,因为 UIKBCandidateCollectionView 类是苹果私有类,不能保证将来它还叫这个名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值