iOS14+下BlocksKit崩潰

iOS 14開始,輸入時使用系統(tǒng)的emoji鍵盤時,使用鍵盤自帶的搜索框TUIEmojiSearchTextField,會導(dǎo)致崩潰。

表情鍵盤

堆棧中注意到來自TUIEmojiSearchTextField的調(diào)用,點(diǎn)擊emoji,就會崩潰。

崩潰信息

從堆??词菬o限循環(huán)調(diào)用keyboardInputChangedSelection:最終導(dǎo)致崩潰,崩潰位置顯示在A2DynamicDelegate.m中。

崩潰

方法一

NSObject+A2BlockDelegate.mbk_registerDynamicDelegateNamed:方法中過濾掉TUIEmojiSearchTextField。

//添加如下代碼
 if (@available(iOS 13.0, *)) {
        if ([delegate isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
             delegate = nil;
      }
 }

+ (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;
        }
        if (@available(iOS 13.0, *)) {
            if ([delegate isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
                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);
    }
}

方法二

修改UITextField+BlocksKit.m處理TUIEmojiSearchTextField

//
//  UITextField+BlocksKit.m
//  BlocksKit
//

#import "UITextField+BlocksKit.h"
#import "A2DynamicDelegate.h"
#import "NSObject+A2BlockDelegate.h"

#pragma mark Delegate

@interface A2DynamicUITextFieldDelegate : A2DynamicDelegate

@end

@implementation A2DynamicUITextFieldDelegate

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldShouldBeginEditing:)])
        ret = [realDelegate textFieldShouldBeginEditing:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)])
        [realDelegate textFieldDidBeginEditing:textField];
    void (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        block(textField);
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldShouldEndEditing:)])
        ret = [realDelegate textFieldShouldEndEditing:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldDidEndEditing:)])
        [realDelegate textFieldDidEndEditing:textField];
    void (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        block(textField);
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
        ret = [realDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    BOOL (^block)(UITextField *, NSRange, NSString *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField, range, string);
    return ret;
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldShouldClear:)])
        ret = [realDelegate textFieldShouldClear:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if (realDelegate && [realDelegate respondsToSelector:@selector(textFieldShouldReturn:)])
        ret = [realDelegate textFieldShouldReturn:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (BOOL)keyboardInputChangedSelection:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if ([textField isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
        return ret;
    }
    if (realDelegate && [realDelegate respondsToSelector:@selector(keyboardInputChangedSelection:)])
        ret = [realDelegate keyboardInputChangedSelection:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (BOOL)keyboardInputChanged:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if ([textField isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
        return ret;
    }
    if (realDelegate && [realDelegate respondsToSelector:@selector(keyboardInputChanged:)])
        ret = [realDelegate keyboardInputChanged:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
    BOOL ret = YES;
    id realDelegate = self.realDelegate;
    if ([textField isKindOfClass:NSClassFromString(@"TUIEmojiSearchTextField")]) {
        return ret;
    }
    if (realDelegate && [realDelegate respondsToSelector:@selector(keyboardInputShouldDelete:)])
        ret = [realDelegate keyboardInputShouldDelete:textField];
    BOOL (^block)(UITextField *) = [self blockImplementationForMethod:_cmd];
    if (block)
        ret &= block(textField);
    return ret;
}

@end

#pragma mark - Category

@implementation UITextField (BlocksKit)

@dynamic bk_shouldBeginEditingBlock, bk_didBeginEditingBlock, bk_shouldEndEditingBlock, bk_didEndEditingBlock, bk_shouldChangeCharactersInRangeWithReplacementStringBlock, bk_shouldClearBlock, bk_shouldReturnBlock;

+ (void)load {
    [self bk_registerDynamicDelegate];
    [self bk_linkDelegateMethods:@{
            @"bk_shouldBeginEditingBlock": @"textFieldShouldBeginEditing:",
            @"bk_didBeginEditingBlock": @"textFieldDidBeginEditing:",
            @"bk_shouldEndEditingBlock": @"textFieldShouldEndEditing:",
            @"bk_didEndEditingBlock": @"textFieldDidEndEditing:",
            @"bk_shouldChangeCharactersInRangeWithReplacementStringBlock": @"textField:shouldChangeCharactersInRange:replacementString:",
            @"bk_shouldClearBlock": @"textFieldShouldClear:",
            @"bk_shouldReturnBlock": @"textFieldShouldReturn:",
    }];
}

- (id)customOverlayContainer {
    return self;
}
@end
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容