首先看一下打算介绍的知识点:

iOS--RAC常见用法(一)

知识点大纲

然后, 就开始One by One了:
(一) RAC的集合:
  • 在RAC中, 也有一个元祖类, 叫做RACTuple, 它完全可以当做OC的数组来用, 比如:

- (void)demo1 {
    /* 元祖 */    RACTuple *tuple = [RACTuple tupleWithObjects:@"firstObject",@"secondObject",@1, nil];    NSString *string = tuple[1];    NSLog(@"%@", string);
}

你同样可以使用以下方法来创建一个元祖:

/// Creates a new tuple out of the array. Does not convert nulls to nils.+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array;/// Creates a new tuple out of the array. If `convert` is YES, it also converts/// every NSNull to RACTupleNil.+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert;/// Creates a new tuple with the given objects. Use RACTupleNil to represent/// nils.+ (instancetype)tupleWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;

在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程


元祖完全可以当做数组来使用, 你也可以通过下标来取出元祖中的数据.

  • 在RAC中, 还有一个非常重要的集合类, 那就是RACSequence, 且看:

- (void)demo2 {    NSArray *array = @[@"jack", @"rose", @"james"];
    [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {        NSLog(@"%@", [NSThread currentThread]);        NSLog(@"%@", x);
    }];
}

遍历一个数组, 打印的结果是:

iOS--RAC常见用法(一)

数组遍历打印结果

可以看到的是: 数组中的元素被一一打印了, 值得注意的是: 这个打印的过程是在子线程调用的, 因为:

+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name {    return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)];
}

在这个方法的调用中, 使用了全局并发队列.

同样的, 还有字典的遍历:

- (void)demo3 {
    NSDictionary *dict = @{
                           @"name" : @"jack",
                           @"age" : @18,
                           };
    [dict.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
        NSLog(@"%@", x);
    }];}

可以看到打印结果是打印了两个元祖类型的对象:

iOS--RAC常见用法(一)

打印了两个元祖类型的对象

那么, 如何将这个元祖类型的对象转化成字典的键值对一一输出呢? 这里就需要用到一个功能强大的宏, 在RAC中, 有很多很强大的宏, 这个宏是这样的:
RACTupleUnpack(...)

我们将需要解析的元祖赋值给这个宏, 同时, 将要解析的key值和value值做为宏的参数, 如下面的代码所示, 我们就能拿到字典的键值对了:

- (void)demo3 {
    NSDictionary *dict = @{
                           @"name" : @"jack",
                           @"age" : @18,
                           };
    [dict.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
        RACTupleUnpack(NSString *key, NSString *value) = x;
        NSLog(@"%@----%@",key,value);
    }];}
  • 还有一点需要单独拿出来讲的就是利用RAC进行字典转模型. RAC提供了一个方法, 可以直接将字典数组映射成模型数组:

- (void)demo4 {    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"网页链接] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {        NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:NULL];        NSArray *infoArr = [[array.rac_sequence.signal map:^id _Nullable(NSDictionary *value) {            return [KFCFood kfcFoodWithDictionary:value];
        }] toArray];        NSLog(@"%@", infoArr);
    }] resume];
}

当我们拿到服务器返回的响应体数据时, 利用json反序列化得到一个字典数组, 然后将数组转化成RACSequence对象,利用其signal属性进行映射, 再调用toArray方法就可以拿到装满模型对象的数组了:

iOS--RAC常见用法(一)

模型数组

(二) RAC基本用法:
  • 代替代理:

iOS--RAC常见用法(一)

需求

假设有如上的需求, 我们一般使用代理来完成. 那么现在不用了, RAC很容易就能解决这个问题:

#import "YFSmallView.h"@implementation YFSmallView- (IBAction)greenButtonDidClick:(UIButton *)sender {    NSLog(@"绿色按钮被点击了");
}@end

我在蓝色View内部定义一个处理点击事件的方法, 然后在控制器中, 响应这个方法产生一个信号, 然后订阅信号, 打印结果是一个元祖:

- (void)demo1 {
    SEL sel = NSSelectorFromString(@"greenButtonDidClick:");
    [[_blueView rac_signalForSelector:sel] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@" ,x);
    }];
}

iOS--RAC常见用法(一)

代替代理


我们可以看到的是:元祖里面保存的是响应的方法的参数, 那么我们可以用解包的方法, 将参数提取出来:

- (void)demo1 {
    SEL sel = NSSelectorFromString(@"greenButtonDidClick:");
    [[_blueView rac_signalForSelector:sel] subscribeNext:^(id  _Nullable x) {
        RACTupleUnpack(UIButton *sender) = x;
        self.view.backgroundColor = sender.backgroundColor;    }];}

通过这个, 我们能够拿到参数sender, 将sender的背景色赋值给控制器view :

iOS--RAC常见用法(一)

运行结果

  • 代替KVO:

    /****************** -------- 代替KVO -------- ******************/- (void)demo2 {
    [_blueView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {        NSLog(@"%@----%@", value, change);
    }];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {    static int x = 50;
    x++;
    _blueView.frame = CGRectMake(x, 50, 100, 100);
}

每点击屏幕就改变_blueView的值, 这时候, 就能够监听的到, 并且在block中进行逻辑处理, 参数value就是当前的keyPath属性对应的值, 参数change是一个字典,

iOS--RAC常见用法(一)

打印结果

不过, 有更方便的监听方法:

[[_blueView rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];

此时, 打印的x的值是当前属性的值.

  • 监听事件:
    以前, 我们监听按钮的点击事件, 我们得这么写代码:

- (void)demo3 {
    [_blueButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonClick:(UIButton *)sender {
    NSLog(@"点击了蓝色按钮+++%@", sender);
}

这样的不好的地方是, 业务逻辑被分割到了另外的地方,显得不统一, 而使用RAC的方法, 我们将逻辑直接写在block代码块里面, 这样可读性更强,使用更方便:

    /****************** -------- 监听事件 -------- ******************/- (void)demo3 {
    [[_blueButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"点击了蓝色按钮---%@", x);
    }];
}
  • 代替通知:

    /****************** -------- 代替通知 -------- ******************/- (void)demo4 {
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        NSLog(@"%@", x);
    }];
}

block中打印的就是通知本身:

iOS--RAC常见用法(一)

通知信息

  • 监听文本框

    /****************** -------- 监听文本框 -------- ******************/- (void)demo5 {
    [self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        _textLabel.text = x;
    }];
}

实现效果:

iOS--RAC常见用法(一)

监听文本框实现效果

(三) 利用RAC定时器创建制作一个发送验证码的小demo

发送验证码是很常见的需求, 点击发送之后, 开始60秒倒计时, 此时按钮不能点击, 且文字变成灰色, 等到60秒时间到后, 便可以重新发送.一般情况下, 我们会用NSTimer, 但RAC为我们提供了更好的定时器方法:

+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler;

需要注意的是, 我们必须在主线程更新UI, 所以scheduler必须是主线程的scheduler, 使用[RACScheduler mainThreadScheduler]这个单例对象作为参数. 主要的代码如下:

self.disposable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {        _time--;        if (_time > 0) {            _sendLabel.text = [NSString stringWithFormat:@"已发送,请等待%@秒", @(_time)];            _sendLabel.textColor = [UIColor lightGrayColor];
            [_sendLabel removeGestureRecognizer:tap];
        }else {            _sendLabel.text = @"重新发送";            _sendLabel.textColor = [UIColor whiteColor];
            [_sendLabel addGestureRecognizer:tap];
            [_disposable dispose];            _time = 10;
        }
    }];

实现效果:

iOS--RAC常见用法(一)

发送验证码实现效果


大神的搬砖者                                   想交流学习    需要资料视频的加群:680565220

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-09
  • 2022-12-23
  • 2021-10-21
  • 2022-12-23
  • 2021-11-27
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案