之前讲了RAC如何帮我们实现KVO / 代理 / 事件 / 通知

今天先不去分析它的核心代码, 我们先看看ReactiveObjC库里面一些特别的东西,  如果大家点开ReactiveObjC目录应该会看到很多category, 今天我们先来看看这些

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

我们先从UITextView+RACSignalSupport.h开始看

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

#import <UIKit/UIKit.h>@class RACDelegateProxy;@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN@interface UITextView (RACSignalSupport)

@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSString *> *)rac_textSignal;@end

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

这里有一个属性跟一个方法,  

关于RACDelegateProxy这个类的用途大概是把初始化传入的代理绑定或者添加给当前正在处理的信号

给大家一个例子:

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

  <ReactiveObjC.h> <objc/runtime.h> ViewController ()<UITextViewDelegate>- (
    RACDelegateProxy *delegateProxy = [[RACDelegateProxy alloc] initWithProtocol:^(RACTuple **textView = [[UITextView alloc] initWithFrame:CGRectMake(, , , ==
    textView.        = (<UITextViewDelegate>

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

这个一般是RAC内部使用, 我们比较少用. 另外也只能处理没有返回值的代理方法

可以到UITextview+RACSignalSupport.m里面看看, 也是类似这样用的

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

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

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

 

好了, 现在我们来使用下这个UITextView类别唯一的方法

- (RACSignal<NSString *> *)rac_textSignal;

大家可以看到, 这个方法会返回一个信号 我们可以对他订阅, 试试看

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    textView.center          = self.view.center;
    textView.backgroundColor = [UIColor greenColor];

    [self.view addSubview:textView];

    [[textView
     rac_textSignal]
     subscribeNext:^(NSString * _Nullable x) {
         
         NSLog(@"%@", x);
     }];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

运行看看, 当我们在textView中输入文字的时候会打印:

2017-07-23 22:41:42.841 RAC[70053:14036438] 12017-07-23 22:41:43.353 RAC[70053:14036438] 112017-07-23 22:41:44.031 RAC[70053:14036438] 111

所以这个x就是Textview的内容了.

 

下面我们看看

UITextField+RACSignalSupport.h

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

#import <UIKit/UIKit.h>@class RACChannelTerminal<ValueType>;@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN@interface UITextField (RACSignalSupport)- (RACSignal<NSString *> *)rac_textSignal;- (RACChannelTerminal<NSString *> *)rac_newTextChannel;@endNS_ASSUME_NONNULL_END

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

这里有两个方法, 我们先看第一个rac_textSignal

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
    
    textField.center          = self.view.center;
    textField.backgroundColor = [UIColor yellowColor];
    
    [[textField
        rac_textSignal]
        subscribeNext:^(NSString * _Nullable x) {
            
            NSLog(@"%@", x);
        }];
    
    [self.view addSubview:textField];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

运行看看, 我们输入数字的时候会打印内容:

2017-07-23 22:55:45.686 RAC[70205:14118946] 12017-07-23 22:55:46.139 RAC[70205:14118946] 112017-07-23 22:55:46.798 RAC[70205:14118946] 111

然后我们看看另外一个方法

- (RACChannelTerminal<NSString *> *)rac_newTextChannel;

这里涉及到了一个类RACChannelTerminal, 我们点进去看看这个类

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

@interface RACChannelTerminal<ValueType> : RACSignal<ValueType> <RACSubscriber>

- (instancetype)init __attribute__((unavailable("Instantiate a RACChannel instead")));// Redeclaration of the RACSubscriber method. Made in order to specify a generic type.- (void)sendNext:(nullable ValueType)value;@end

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

可以看到它是一个RACSignal的子类,  我们先调用看看这个方法

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

[[textField
        rac_newTextChannel]
        subscribeNext:^(NSString * _Nullable x) {
            
            NSLog(@"%@", x);
        }];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

效果跟rac_textSignal一样, 那么它有什么特别的用法呢

它的作用是做双向绑定 关于什么是双向绑定呢? 给大家一个简单的例子:

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    UITextField *textFieldA = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
    
    textFieldA.center          = self.view.center;
    textFieldA.backgroundColor = [UIColor yellowColor];
    
    [self.view addSubview:textFieldA];
    
    UITextField *textFieldB = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
    
    textFieldB.center          = CGPointMake(self.view.center.x, self.view.center.y + 50);
    textFieldB.backgroundColor = [UIColor yellowColor];
    
    [self.view addSubview:textFieldB];
    
    RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];
    RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];
    

    [terminalA subscribe:terminalB];
    [terminalB subscribe:terminalA];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

运行可以看到, 改变textFieldA的值textFieldB的值也会跟着改变, 反过来也一样.

这里如果要实现双向绑定, 其实还有一个简单的方法:

RACChannelTo(textFieldA, text) = RACChannelTo(textFieldB, text);

大家可以试试看.

 

如果我们不仅仅想让两个绑定对象之间的值简单的相等而已呢? 比如textFieldA的值是123的时候textFieldB的值要为321要怎么处理呢?

这里我们先说一个一会用到的方法: map

map方法,将会创建一个和原来一模一样的信号,只不过新的信号传递的值变为了block(value)。

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    [[[textField
        rac_textSignal]
        map:^id _Nullable(NSString * _Nullable value) {            
            if ([value isEqualToString:@"11"]) {                
                return @"1";
            } else {                
                return @"0";
            }
        }] subscribeNext:^(id  _Nullable x) {
            
            NSLog(@"%@", x);
        }];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

运行看看, 当我们输入1, 会打印0, 输入11的时候会打印1, 这里就是把传递的值从textField的text转变成为我们的1 和 0;

然后有个特别的地方, 加入我们知道传递的值的类型, 我们就可以直接把后面订阅的block里面的参数类型直接改成我们知道的类型

例如把id改为NSString *运行结果也是一样的, 这个是RAC一个比较特别的地方

 

那么要实现上面的123 到 321可以这样写:

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];
    RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];
    
    [[terminalA
        map:^id _Nullable(id  _Nullable value) {            
            if ([value isEqualToString:@"123"]) {                
                return @"321";
            }            
            return value;
        }]
        subscribe:terminalB];

    [terminalB subscribe:terminalA];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

大家可以自己运行看看效果, 当textFieldA输入123的时候textFieldB会变为321

 

下面我们看看

UIActionSheet+RACSignalSupport.h

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

#import <UIKit/UIKit.h>@class RACDelegateProxy;@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN@interface UIActionSheet (RACSignalSupport)

@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSNumber *> *)rac_buttonClickedSignal;@end

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

rac_delegateProxy跟之前textview是一样的用法这里开始就不再解释这类属性了

我们直接试着使用rac_buttonClickedSignal

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"RAC ActionSheet" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"OK" otherButtonTitles:@"Other", nil];
    
    [[actionSheet
        rac_buttonClickedSignal]
     subscribeNext:^(NSNumber * _Nullable x) {
         
         NSLog(@"%@", x);
     }];
    
    [actionSheet showInView:self.view];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

运行看看, x是actionSheet上按钮的编号, 我们拿到编号就可以做响应的事件处理了.

 

UIAlertView+RACSignalSupport.h

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

@interface UIAlertView (RACSignalSupport)

@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;- (RACSignal<NSNumber *> *)rac_buttonClickedSignal;- (RACSignal<NSNumber *> *)rac_willDismissSignal;@endNS_ASSUME_NONNULL_END

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

它有两个方法, 一个是点击的时候用, 一个是dismiss的时候用

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Alert" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    
    [[alert
        rac_buttonClickedSignal]
        subscribeNext:^(NSNumber * _Nullable x) {
            
            NSLog(@"click: x");
        }];
    
    [[alert
        rac_willDismissSignal]
        subscribeNext:^(NSNumber * _Nullable x) {
            
            NSLog(@"dismiss: %@", x);
        }];
    
    [alert show];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

 

UIControl+RACSignalSupport.h

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

#import <UIKit/UIKit.h>@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN@interface UIControl (RACSignalSupport)- (RACSignal<__kindof UIControl *> *)rac_signalForControlEvents:(UIControlEvents)controlEvents;@endNS_ASSUME_NONNULL_END

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

只有一个方法, 这个之前讲过是做UIControllerEvent处理的, 再给个例子:

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    
    [button setFrame:CGRectMake(0, 0, 100, 35)];
    [button setCenter:self.view.center];
    [button setBackgroundColor:[UIColor yellowColor]];
    [button setTitle:@"按钮" forState:UIControlStateNormal];
    
    [[button
        rac_signalForControlEvents:UIControlEventTouchUpInside]
        subscribeNext:^(__kindof UIControl * _Nullable x) {
            
            NSLog(@"点击了按钮");
            x.backgroundColor = [UIColor redColor];
        }];
    
    [self.view addSubview:button];

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

 

UIDatePicker+RACSignalSupport.h

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

#import <UIKit/UIKit.h>@class RACChannelTerminal<ValueType>;

NS_ASSUME_NONNULL_BEGIN@interface UIDatePicker (RACSignalSupport)- (RACChannelTerminal<NSDate *> *)rac_newDateChannelWithNilValue:(nullable NSDate *)nilValue;@endNS_ASSUME_NONNULL_END

万码学堂,电脑培训,计算机培训,Java培训,JavaEE开发培训,青岛软件培训,软件工程师培训

它只有一个绑定的方法, 直接给大家一个例子:

大概效果为我们在Controller中添加一个UITextField跟一个UIDatePicker, 然后获取他们的RACChannelTerminal,

http://www.cnblogs.com/zhouxihi/p/7226917.html