iOS14+下BlocksKit崩潰

iOS 14開始疾渴,輸入時(shí)使用系統(tǒng)的emoji鍵盤時(shí),使用鍵盤自帶的搜索框TUIEmojiSearchTextField新思,會(huì)導(dǎo)致崩潰姜性。

表情鍵盤

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

崩潰信息

從堆棧看是無限循環(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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鞭衩,一起剝皮案震驚了整個(gè)濱河市学搜,隨后出現(xiàn)的幾起案子娃善,更是在濱河造成了極大的恐慌,老刑警劉巖瑞佩,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聚磺,死亡現(xiàn)場離奇詭異,居然都是意外死亡炬丸,警方通過查閱死者的電腦和手機(jī)瘫寝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稠炬,“玉大人焕阿,你說我怎么就攤上這事∈灼簦” “怎么了暮屡?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毅桃。 經(jīng)常有香客問我褒纲,道長,這世上最難降的妖魔是什么钥飞? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任莺掠,我火速辦了婚禮,結(jié)果婚禮上读宙,老公的妹妹穿的比我還像新娘彻秆。我一直安慰自己,他們只是感情好论悴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布掖棉。 她就那樣靜靜地躺著,像睡著了一般膀估。 火紅的嫁衣襯著肌膚如雪幔亥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天察纯,我揣著相機(jī)與錄音帕棉,去河邊找鬼。 笑死饼记,一個(gè)胖子當(dāng)著我的面吹牛香伴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播具则,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼即纲,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了博肋?” 一聲冷哼從身側(cè)響起低斋,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蜂厅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膊畴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掘猿,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年唇跨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稠通。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡买猖,死狀恐怖改橘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情政勃,我是刑警寧澤唧龄,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站奸远,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讽挟。R本人自食惡果不足惜懒叛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耽梅。 院中可真熱鬧薛窥,春花似錦、人聲如沸眼姐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽众旗。三九已至罢杉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贡歧,已是汗流浹背滩租。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留利朵,地道東北人律想。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像绍弟,于是被迫代替她去往敵國和親技即。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容