解决iOS14Emoji表情Search崩溃
2021-09-27 本文已影响0人
iOS_zy

iOS 14 开始,系统的 emoji 键盘内部有一个搜索框 TUIEmojiSearchTextField,这个搜索框如果在 init 的时候设置 delegate(或者设置了keyboardAppearance) 会导致触发死循环,目前我们并不需要为这个新的系统TF做代理,所以需要过滤掉它。
我出错的位置是BlocksKit里面改用了“TUIEmojiSearchTextField”的delegate。BlocksKit会在把delegate变成block使用,非常方便,但是这里明显是转换了一个我们并不需要的delegate所以在BlocksKit获取delegate的地方过滤它。
通过断点,我发现会有一个TUIEmojiSearchTextField的delegate在“bk_registerDynamicDelegateNamed:forProtocol:”方法中被调用,它主要功能就是修改 getter 和 setter 方法,将原有的 delegate 转发到 realDelegate,修改原有的 delegate 的实现。下图即是bk_registerDynamicDelegateNamed:forProtocol方法。
+ (void)bk_registerDynamicDelegateNamed:(NSString *)delegateName forProtocol:(Protocol *)protocol
{
NSMapTable *propertyMap = [self bk_delegateInfoByProtocol:YES];
A2BlockDelegateInfo *infoAsPtr = (__bridge void *)[propertyMap objectForKey:protocol];
if (infoAsPtr != NULL) { return; }
const char *name = delegateName.UTF8String;
objc_property_t property = class_getProperty(self, name);
SEL setter = setterForProperty(property, name);
SEL a2_setter = prefixedSelector(setter);
SEL getter = getterForProperty(property, name);
A2BlockDelegateInfo info = {
setter, a2_setter, getter
};
[propertyMap setObject:(__bridge id)&info forKey:protocol];
infoAsPtr = (__bridge void *)[propertyMap objectForKey:protocol];
IMP setterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject, id delegate) {
A2DynamicDelegate *dynamicDelegate = getDynamicDelegate(delegatingObject, protocol, infoAsPtr, YES);
if ([delegate isEqual:dynamicDelegate]) {
delegate = nil;
}
dynamicDelegate.realDelegate = delegate;
});
if (!swizzleWithIMP(self, setter, a2_setter, setterImplementation, "v@:@", YES)) {
bzero(infoAsPtr, sizeof(A2BlockDelegateInfo));
return;
}
if (![self instancesRespondToSelector:getter]) {
IMP getterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject) {
return [delegatingObject bk_dynamicDelegateForProtocol:a2_protocolForDelegatingObject(delegatingObject, protocol)];
});
addMethodWithIMP(self, getter, NULL, getterImplementation, "@@:", NO);
}
}
在imp_implementationWithBlock中,加入判断代码:
if(@available(iOS 13.0, *)) {
if([delegate isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
delegate = nil;
}
}
代码位置如下:

文章方法参考自腾讯的QMUI的1042问题:Tencent/QMUI_iOS/issues/1042