ios

RAC给UITextField添加代理回调

2020-03-08  本文已影响0人  Dawn_wdf

使用RAC监听UITextField的文本可以用rac_textSignal,但是rac_textSignal是实时监控,如果我想等待UITextField输入完毕,即调用textFieldDidEndEditing:时发送信号,目前RAC中并没有支持,我参考RAC中UITextView+RACSignalSupport.h改写了一版。代码如下:
.h

//
//  UITextField+ RACDelegateSignalSupport.h
//  Snatch
//
//  Created by DawnWang on 2020/3/6.
//  Copyright © 2020 Dawn Wang. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UITextField (RACDelegateSignalSupport)
- (RACSignal *)rac_keyboardReturnSignal;
- (RACSignal *)rac_textFieldDidEndEditing;

@end

NS_ASSUME_NONNULL_END

.m

//
//  UITextField+ RACDelegateSignalSupport.m
//  Snatch
//
//  Created by DawnWang on 2020/3/6.
//  Copyright © 2020 Dawn Wang. All rights reserved.
//

#import "UITextField+ RACDelegateSignalSupport.h"
#import <objc/runtime.h>
#import <ReactiveObjC/ReactiveObjC.h>
#import "NSObject+RACDescription.h"

@interface UITextField()

@property (nonatomic, weak) RACDelegateProxy *rac_delegateProxy;

@end

@implementation UITextField (RACDelegateSignalSupport)

static void RACUseDelegateProxy(UITextField *self) {
    if (self.delegate == self.rac_delegateProxy) return;

    self.rac_delegateProxy.rac_proxiedDelegate = self.delegate;
    self.delegate = (id)self.rac_delegateProxy;
}

- (RACDelegateProxy *)rac_delegateProxy {
    RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);
    if (proxy == nil) {
        proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextFieldDelegate)];
        objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    return proxy;
}

- (RACSignal *)rac_keyboardReturnSignal {
    
    @weakify(self);
    RACSignal *signal = [[[[[RACSignal defer:^{
        @strongify(self);
           
        return [RACSignal return:RACTuplePack(self)];
    }]
                            concat:[self.rac_delegateProxy signalForSelector:@selector(textFieldShouldReturn:)]]
                           reduceEach:^(UITextField *x) {
    //因为此信号的本质是重置了代理,所以如果直接return X,原来代理方法则不执行,添加如下方法让原来的代理去执行,rac_textFieldDidEndEditing信号量同理。
    //让原来的代理也执行的原因是,我在自定义的view中添加了textfield并设置代理,希望点击return键的时候处理一些统一的事件,比如[textField resignFirstResponder];,
   //而在VC中配置了信号量处理特殊的业务逻辑。这样就可以在处理不同的业务逻辑之前,先处理统一的业务。
        @strongify(self);
        __autoreleasing id delegate = self.rac_delegateProxy.rac_proxiedDelegate;
        if ([delegate respondsToSelector:@selector(textFieldShouldReturn:)]) {
            [delegate textFieldShouldReturn:x];
        }
        return x;
    }]
                          takeUntil:self.rac_willDeallocSignal]
                         setNameWithFormat:@"%@ -rac_keyboardReturnSignal", RACDescription(self)];
    RACUseDelegateProxy(self);
                      
                       
    return signal;
}

- (RACSignal *)rac_textFieldDidEndEditing {
    @weakify(self);
     RACSignal *signal = [[[[[RACSignal
         defer:^{
             @strongify(self);
             return [RACSignal return:RACTuplePack(self)];
         }]
         concat:[self.rac_delegateProxy signalForSelector:@selector(textFieldDidEndEditing:)]]
                           reduceEach:^(UITextField *x) {
         @strongify(self);
         __autoreleasing id delegate = self.rac_delegateProxy.rac_proxiedDelegate;
         if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:)]) {
             [delegate textFieldDidEndEditing:x];
         }
                               return x;
                           }]
                           takeUntil:self.rac_willDeallocSignal]
         setNameWithFormat:@"%@ -rac_textFieldDidEndEditing", RACDescription(self)];

     
     RACUseDelegateProxy(self);
                       
                        
     return signal;
}

@end
上一篇下一篇

猜你喜欢

热点阅读