iOS -RAC利用

开发者 2024-9-2 09:29:50 19 0 来自 中国
一、简介

ReactiveCocoa 可以说是联合了函数式编程和相应式编程的框架,也可称其为函数相应式编程(FRP)框架,夸大一点,RAC 最大的优点是提供了一个单一的、同一的方法行止理处罚异步的举动,包括 delegate 方法, blocks 回调,target-action 机制,notifications 和 KVO。
导入

在项目的 podfile 文件中添加
# RAC  pod 'ReactiveObjC'在利用时导入
#import <ReactiveObjC/ReactiveObjC.h>二、根本利用

1.button 添加点击变乱

    [[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {        //button点击    }];2.取代 KVO 监听

#import "ViewController.h"#import <ReactiveObjC/ReactiveObjC.h>@interface ViewController ()@property(nonatomic,assign)NSInteger num;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = [UIColor whiteColor];    UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(50, 100, 100, 100)];    button.backgroundColor = [UIColor orangeColor];    @weakify(self);    //subscribeNext 收到信号    [[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {        @strongify(self);        //button点击        self.num++;    }];    [self.view addSubview:button];    //RACObserve(TARGET, KEYPATH):监听某个对象的某个属性,返回的是一个信号    [RACObserve(self,num) subscribeNext:^(id  _Nullable x) {        //        NSLog(@"%@",x);    }];    //忽略值为 1 的环境,不实验回调    [[RACObserve(self, num) ignore1]subscribeNext:^(id  _Nullable x) {        NSLog(@"忽略%@",x);    }]; }@end3.监听输入变革

    self.textField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];    [self.view addSubview:self.textField];    [[self.textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {        NSLog(@"%@",x);    }];4.关照回调

    //RAC监听回调    [[[NSNotificationCenter defaultCenter] rac_addObserverForName"DJTESTNOTI" object:nil] subscribeNext:^(NSNotification * _Nullable x) {            NSLog(@"x===%@",x);    }];        //发送关照    [[NSNotificationCenter defaultCenter] postNotificationName"DJTESTNOTI" object"444"];5.手势回调

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];    [self.view addGestureRecognizer:tap];    [[tap rac_gestureSignal] subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {        NSLog(@"点击");    }];6.数组和字典遍历

    //数组遍历    NSArray *array = @[@"111",@"222",@"333",@"444"];    [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {        NSLog(@"数组%@",x);    }];    //字典遍历    NSDictionary *dict = @{@"111""-111",@"222""-222",@"333""-333",@"444""-444"};    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {        NSLog(@"字典%@",x);    }];二、宏

1. RAC

RAC(TARGET, [KEYPATH, [NIL_VALUE]])用于给某个对象的某个属性绑定
// 给某个对象的某个属性绑定一个信号,只要产生信号,就会把信号的内容给对象的属性举行赋值 // 给label的text属性绑定一个输入值的信号 RAC(self.titleLabel,text) = RACObserve(self, inputContentText);2.RACObserve

RACObserve(TARGET, KEYPATH)监听某个对象的某个属性,返回的是一个信号
3.RACTuplePack和RACTupleUnpack

RACTuplePack把数据包装成 RACTuple(元组类),被包装的数据必须是 object 类数据
   // RACTuplePack:把一些数据包装成元组类,可用于信号间的数据传输   // 注意:被包装的数据必须是 object类数据   RACTuple *tuple = RACTuplePack(@"数据1",@1,@[@"1",@"2",@"3",@"4"]);RACTupleUnpack把 RACTuple(元组类)解包成对应的数据,解包参数的次序及数据范例要和包装数据时的次序及范例保持同等
  // 参数:必要剖析数据天生出来对应的变量名  // 注意:解包参数的次序及数据范例要和包装数据时的次序及范例保持同等  RACTupleUnpack(NSString  *str,NSNumber  *num, NSArray *arr) = tuple;三、信号组合

1. concat

concat按肯定次序拼接信号,当多个信号发出的时间,有次序的吸收信号,依赖关系把一组信号串联起来,前面一个信号 complete,背面一个信号才开始发挥作用。
    //好比A哀求依赖B哀求,只有B哀求完成之后才华实验A哀求或操纵    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext"signalA"];        return nil;    }];        RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext"signalB"];        //因为A依赖B,以是只必要在B内里声明发送完成        [subscriber sendCompleted];        return nil;    }];        //注意点:如果一个操纵背面还被其他操纵依赖,好比signalB,必要在其内部发送完数据后声明发送完成,[subscriber sendCompleted];    RACSignal *contatSignal = [signalB concat:signalA];        [contatSignal subscribeNext:^(id x) {        NSLog(@"(concat)效果:%@",x);        //输出效果            }];2.then

then用于毗连两个信号,当第一个信号完成,才会毗连 then 返回的信号。
    //A哀求依赖B哀求,只有B哀求完成之后才华实验A的哀求或操纵,必要注意:这个方法最后只能拿到A的值,如果B不必要传值,只必要先举行某些操纵的时间可以用then    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalA"];        return nil;    }];        RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalB"];        [subscriber sendCompleted];        return nil;    }];        RACSignal *thenSignal = [signalB then:^RACSignal *{        return signalA;    }];        [thenSignal subscribeNext:^(id x) {        NSLog(@"(then)效果:%@",x);        //输出效果    }];then 与 concat 区别:then 监听不到第一个信号的值,共同点都是必须第一个信号完成,第二个信号才会激活
3. merge

merge 把多个信号归并为一个信号,任何一个信号有新值的时间就会调用。
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {            [subscriber sendNext:@"signalA"];            return nil;        }];            RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalB"];        [subscriber sendCompleted];        return nil;    }];        RACSignal *mergeSignal = [signalA merge:signalB];        [mergeSignal subscribeNext:^(id x) {        NSLog(@"(merge)效果:%@",x);    }];4. zipWith

zipWith 把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,而且把两个信号的内容归并成一个元组,才会触发压缩流的 next 变乱。
    //信号压缩,这个方法实在和rac_liftSelector本质时一样的,把多个信号压缩成一个信号,只有被压缩的信号全部发出消息时才华调用    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalA"];        return nil;    }];        RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalB"];        return nil;    }];        //zipSignal是有次序的    RACSignal *zipSignal = [signalB zipWith:signalA];        [zipSignal subscribeNext:^(id x) {        //x是担当到的全部数据包装成的元组        NSLog(@"(zipWith)效果:%@",x);        //输出效果        /*--TIME:14:53:55.966000+0800        (zipWith)效果:<RACTwoTuple: 0x600003a2df90> (            signalB,            signalA        )*/    }];5. reduce

reduce信号聚合,参数必要本身添加
    //多用于登录逻辑    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalA"];        return nil;    }];    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"signalB"];        return nil;    }];        // 聚合    // reduce:信号聚合,参数必要本身添加    // 常见的用法,(先组合再聚合)。combineLatestid<NSFastEnumeration>)signals reduceid (^)())reduceBlock    // reduce中的block简介:    // reduceblcok中的参数,有多少信号组合,reduceblcok就有多少参数,每个参数就是之前信号发出的内容    // reduceblcok的返回值:聚合信号之后的内容。    RACSignal *combineSignal = [RACSignal combineLatest:@[signalA, signalB] reduce:^id(NSString *signalA, NSString *signalB){        NSLog(@"%@----%@", signalA, signalB);        //block:只要恣意一个信号发出内容,就会调用        //block参数个数:由信号决定        //block参数范例:block的参数就是信号发出值        //把两个信号中的值聚合成哪个值        return @(signalA.length && signalB.length);    }];        [combineSignal subscribeNext:^(id x) {        NSLog(@"(combineLatest)效果:%@",x);        //输出效果        //--TIME:14:53:55.966000+0800 (combineLatest)效果:1    }];        [[signalA combineLatestWith:signalB] subscribeNext:^(id  _Nullable x) {            //x是吸收两个信号归并后的数据包装成的元组(RACTuple)        NSLog(@"(combineLatestWith)效果:%@",x);        //输出效果       /*--TIME:14:53:55.966000+0800        (combineLatestWith)效果:<RACTwoTuple: 0x600003578620> (            signalA,            signalB        )        */    }];6.其他

combineLatest将多个信号归并起来,而且拿到各个信号的最新的值,必须每个归并的 signal 至少都有过一次 sendNext,才会触发归并的信号。
combineLatestWith 归并两个信号,当两个信号都有 sendNext 才会触发归并的信号。
四、MVVM+RAC

示比方下:
DJViewController

#import <UIKit/UIKit.h>@interface DJViewController : UIViewController@end#import "DJViewController.h"#import "DJViewModel.h"#import "DJTableViewCell.h"@interface DJViewController ()<UITableViewDataSource, UITableViewDelegate>@property (strong, nonatomic)  UITableView *tableView;@property (strong, nonatomic) DJViewModel *reqVM;@end@implementation DJViewController- (void)viewDidLoad {   [super viewDidLoad];    self.view.backgroundColor = [UIColor whiteColor];   [self setUI];   [self ViewModelEvent];}#pragma mark - 界面设置- (void)setUI {    self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 100)];   self.tableView.dataSource = self;   self.tableView.delegate = self;    [self.view addSubview:self.tableView];}#pragma mark - ViewModel变乱- (void)ViewModelEvent {   [self.reqVM.reqCommand execute:nil];   @weakify(self);   [self.reqVM.refreshUISubject subscribeNext:^(id x) {      @strongify(self);      [self.tableView reloadData];   }];}#pragma mark - UITableView设置- (NSInteger)tableViewUITableView *)tableView numberOfRowsInSectionNSInteger)section{   return self.reqVM.dataArray.count;}- (UITableViewCell *)tableViewUITableView *)tableView cellForRowAtIndexPathNSIndexPath *)indexPath{   DJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"OrderCell"];    if (!cell) {        cell = [[DJTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"OrderCell"];    }   cell.model = self.reqVM.dataArray[indexPath.row];   return cell;}-(CGFloat)tableViewUITableView *)tableView heightForRowAtIndexPathNSIndexPath *)indexPath{    return 80;}#pragma mark - 懒加载- (DJViewModel *)reqVM {   if (!_reqVM) {      _reqVM = [[DJViewModel alloc] init];   }   return _reqVM;}@end

  • [self.reqVM.reqCommand execute:nil]; 方法为实验 reqCommand 变乱下令,reqCommand 是 DJViewModel 中网络哀求变乱。
  • [self.reqVM.refreshUISubject subscribeNext:^(id x) { @strongify(self); [self.tableView reloadData]; }];
    此方法为订阅 DJViewModel 中网络哀求完成时发送的信号(refreshUISubject),也就是说当网络哀求完成之后会实验 block 中的革新 tableView 方法。
DJViewModel

#import <Foundation/Foundation.h>#import <ReactiveObjC/ReactiveObjC.h>@interface DJViewModel : NSObject@property (nonatomic, strong) RACSubject *refreshUISubject;@property (strong, nonatomic) RACCommand *reqCommand;@property (nonatomic, strong) NSArray *dataArray;@end#import "DJViewModel.h"#import "DJModel.h"@interface DJViewModel ()@end@implementation DJViewModel- (instancetype)init {    if (self = [super init]) {        [self or_initialize];    }    return self;}- (void)or_initialize {    //网络哀求信号    [self.reqCommand.executionSignals.switchToLatest subscribeNext:^(NSDictionary *dic) {        NSArray *items = dic[@"items"];        NSMutableArray *arr = [NSMutableArray array];        for (NSDictionary * dict in items) {            DJModel *model = [[DJModel alloc]init];            model.name = dict[@"name"];            [arr addObject:model];        }        self.dataArray = [arr copy];        [self.refreshUISubject sendNext:nil];    }];    [[self.reqCommand.executing skip:1] subscribeNext:^(id x) {        if ([x isEqualToNumber:@(YES)]) {//            [MBProgressHUD showCircleHud:nil];        }else {//            [MBProgressHUD closeHud:nil];        }    }];}#pragma mark - 懒加载- (RACCommand *)reqCommand {    if (!_reqCommand) {        _reqCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {            //因为要把哀求的数据传出去,以是要把网络哀求包装在信号里            RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {                //网络哀求                NSDictionary *dic = @{@"items":@[@{@"name":@"hhhh"}]};                [subscriber sendNext:dic];                [subscriber sendCompleted];                return nil;            }];            //返回网络哀求信号            return signal;        }];    }    return _reqCommand;}- (RACSubject *)refreshUISubject {    if (!_refreshUISubject) {        _refreshUISubject = [RACSubject subject];    }    return _refreshUISubject;}- (NSArray *)dataArray {    if (!_dataArray) {        _dataArray = [[NSArray alloc] init];    }    return _dataArray;}@end

  • refreshUISubject 属性是关照控制器革新 UI 的信号,其功能类似于署理。reqCommand 属性是网络哀求变乱,袒露在 .h 文件的缘故原由是让控制器来决定什么时间发起变乱,也就是说什么时间发起网络哀求。
  • or_initialize 中第一个方法是订阅 reqCommand(网络哀求)变乱中的信号发出的值,也就是网络哀求乐成后发送的数据。第二个方法的功能是监听 reqCommand 变乱过程,其 block 中的值返回 YES 是,代表变乱正在实验,以是在这内里可以加一个正在加载的菊花,当返回值为 NO 时,代表变乱实验完成,把正在加载菊花去掉。
  • 懒加载 - (RACCommand *)reqCommand 方法中就是网络哀求变乱,block 内里的 signal 信号作用是把网络哀求的数据发送给 or_initialize 中第一个方法的订阅者。订阅者拿到数据后实验字典转模子操纵,然后发送袒露在 .h 文件中的  refreshUISubject 信号给订阅此信号的控制器,关照他革新 tableView。
DJViewModel、DJTableViewCell

#import <Foundation/Foundation.h>@interface DJModel : NSObject@property(nonatomic,assign)NSInteger num;@end#import "DJModel.h"@implementation DJModel@end#import <UIKit/UIKit.h>#import "DJModel.h"@interface DJTableViewCell : UITableViewCell@property (nonatomic, strong) DJModel *model;@end#import "DJTableViewCell.h"@interface DJTableViewCell ()@end@implementation DJTableViewCell- (void)setModelDJModel *)model {    self.textLabel.text = model.name;}@end
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 18:23, Processed in 0.163866 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表