RAC常用清单

RACSignal:

一:创建方法:

+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe;

+ (RACSignal *)error:(NSError *)error;

+ (RACSignal *)return:(ValueType)value;

+ (RACSignal *)empty;

二:操作相关:

1.timeOut:超时,可以让一个信号在一定的时间后,自动报错。

[[[RACSignal createSignal:^RACDisposable *(id subscriber) {

    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{

        [subscriber sendNext:@"rac"];

        [subscriber sendCompleted];

    }];

    return nil;

}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]]

    subscribeNext:^(id x) {

    //TODO

} error:^(NSError *error) {

    //TODO

} completed:^{

    //TODO

}];

2.then:有两部分数据:想让上部分先进行网络请求但是过滤掉数据,然后进行下部分的,拿到下部分数据 

// 创建信号A 

RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    NSLog(@"----发送上部分请求---"); 

    [subscriber sendNext:@"上部分数据"]; 

    [subscriber sendCompleted]; // 必须调用sendCompleted方法! 

    return nil; 

}]; 


// 创建信号B 

RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    // 发送请求 

    NSLog(@"--发送下部分请求--"); 

    [subscriber sendNext:@"下部分数据"]; 

    [subscriber sendCompleted]; 

    return nil; 

}]; 

// 创建组合信号 

RACSignal *thenSignal = [signalA then:^RACSignal *{ 

    return signalB; 

}]; 


// 订阅信号 

[thenSignal subscribeNext:^(id x) { 

    NSLog(@"%@", x); 

}];

3.zipWith:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。

RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {

    [subscriber sendNext:@1];

    return nil;

}];


RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) {

    [subscriber sendNext:@2];

    return nil;

}];


// 压缩信号A,信号B

RACSignal *zipSignal = [signalA zipWith:signalB];

[zipSignal subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

元组内元素的顺序不会变,跟发送的顺序无关,而是跟压缩的顺序有关[signalA zipWith:signalB]---先是A后是B

底层实现:

1.定义压缩信号,内部就会自动订阅signalA,signalB

2.每当signalA或者signalB发出信号,就会判断signalA,signalB有没有发出个信号,有就会把最近发出的信号都包装成元组发出。

等同于下面的写法

[[RACSignal combineLatestWith:@[signalA, signalB] subscribeNext:^(id x) {

    //TODO

}];

4.retry重试只要失败,就会重新执行创建信号中的block,直到成功.

__block int i = 0;

[[[RACSignal createSignal:^RACDisposable *(id subscriber) {

    if (i == 10) {

        [subscriber sendNext:@1];

    }else{

        NSLog(@"接收到错误");

        [subscriber sendError:nil];

    }

    i++;

    return nil;

}] retry] subscribeNext:^(id x) {

    NSLog(@"%@",x);

} error:^(NSError *error) {


}];

5.throttle节流:在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出

RACSubject *signal = [RACSubject subject];

[[signal throttle:1] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

[signal sendNext:@"test"];

6.interval定时:每隔一段时间发出信号(基本上算是rac定时器了)

[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

7.delay:延迟发送

①RACSignal *signal = [[[RACSignal createSignal:^RACDisposable *(id subscriber) {

    [subscriber sendNext:@1];

    return nil;

}] delay:2] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

②[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{ 

    //TODO 

}];

8.take:从开始一共取N次的信号。takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号.takeUntil:获取信号直到某个信号执行完成

RACSubject *signal = [RACSubject subject];

[[signal take:1] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

[signal sendNext:@1];

[signal sendNext:@2];

9.concat:有两部分数据:想让上部分先执行,完了之后再让下部分执行(都可获取值), 如果A发送失败,B也不会执行。A和B是依赖关系

RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    [subscriber sendNext:@"上部分数据"]; 

    [subscriber sendCompleted]; // 必须要调用sendCompleted方法! 

    return nil; 

}]; 

RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    [subscriber sendNext:@"下部分数据"]; 

    return nil; 

}]; 

// concat:按顺序去链接 

RACSignal *concatSignal = [signalA concat:signalsB]; 

// 订阅组合信号 

[concatSignal subscribeNext:^(id x) { 

    NSLog(@"%@",x); 

}];

10.RAC线程切换

RACScheduler *backgroundScheduler = [RACScheduler scheduler];

RACSignal *testSignal = [[RACSignal

createSignal:^RACDisposable *(id subscriber) {

    // 这段代码会运行在子线程

    [subscriber sendNext:@1];

    [subscriber sendCompleted];

    return nil;

}]

subscribeOn:backgroundScheduler];

[[testSignal deliverOn: [RACScheduler mainThreadScheduler]] subscribeNext:^(id _Nullable x) {

    NSLog(@"在主线程执行");

}];

takeLast表示倒数的前两次

接下来是几个block回调方法

takeWhileBlock BOOL值,意思是当返回YES的时候,订阅者才能收到信号

skipWhileBlock BOOL值,意思是当返回YES的时候,订阅者就会跳过信号,NO的时候才接受

skipUntilBlock BOOL值,意思是 返回NO的时候,不会收到消息, 直到返回YES的时候才开始收消息。

distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求

11.merge: 把多个信号合并为一个信号,任何一个信号有新值的时候就会调用

RACSubject *signalA = [RACSubject subject];

RACSubject *signalB = [RACSubject subject];

RACSignal *signals = [signalA merge:signalB];

[signals subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

[signalA sendNext:@1];

[signalB sendNext:@2];

[signalB sendNext:@3];

12.combineLatest: reduce:把validUsernameSignal和validPasswordSignal产生的最新的值聚合在一起,并生成一个新的信号。每次这两个源信号的任何一个产生新值时,reduce block都会执行,block的返回值会发给下一个信号

RACSignal *signUpActiveSignal =

[RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]

reduce:^id(NSNumber *usernameValid, NSNumber *passwordValid) {

    return @([usernameValid boolValue] && [passwordValid boolValue]);

}];

combineLatest:将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号。

reduce聚合:用于信号发出的内容是元组,把信号发出元组的值聚合成一个值。reduceblcok中的参数,有多少信号组合,reduceblcok就有多少参数,每个参数就是之前信号发出的内容

reduceblcok的返回值:聚合信号之后的内容。

rac_liftSelector:withSignals 也是类似,当signalA和signalB都至少sendNext过一次,接下来只要其中任意一个signal有了新的内容,相应方法就会自动被调用。

13.skip:表示输入第几次,不会被监听到,跳过第几次发出的信号

[[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

14.distinctUntilChanged:过滤,当上一次和当前的值不一样,就会发出内容

[[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

15.filter:过滤信号,使用它可以获取满足条件的信号

[_textField.rac_textSignal filter:^BOOL(NSString *value) {

    return value.length > 3;

}];

16.ignore:忽略某些值的信号

[[_textField.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

17.startWith:startWith:@"123"等同于[subscriber sendNext:@"123"] 也就是第一个发送

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {

    //[subscriber sendNext:@"123"];//startWith:@"123"等同于这句话

    [subscriber sendNext:@"rac"];

    [subscriber sendCompleted];

    return nil;

}] startWith:@"123"];

[signal subscribeNext:^(id x) {


}];

18.switchToLatest:只能用于signalOfSignals(信号的信号)

RACSubject *signalOfSignals = [RACSubject subject];

RACSubject *signal = [RACSubject subject];

[signalOfSignals.switchToLatest subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

[signalOfSignals sendNext:signal];

[signal sendNext:@1];

19.

doNext: 执行Next之前,会先执行这个Block

doCompleted: 执行sendCompleted之前,会先执行这个Block

[[[[RACSignal createSignal:^RACDisposable *(id subscriber) {

    [subscriber sendNext:@1];

    [subscriber sendCompleted];

    return nil;

}] doNext:^(id x) {

    // 执行[subscriber sendNext:@1];之前会调用这个Block

}] doCompleted:^{

    // 执行[subscriber sendCompleted];之前会调用这个Block

}]];

一个页面多个网络请求:

①rac_liftSelector:withSignalsFromArray:Signals:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法

RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    [subscriber sendNext:@"发送请求1"]; 

    return nil; 

}]; 

RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    [subscriber sendNext:@"发送请求2"]; 

    return nil; 

}]; 

// 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。 

[self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];

②接口串联 

@weakify(self)

RACSignal *finalSignal = [[self fetchData]

flattenMap:^RACSignal *(NSString *dataResult) {

    @strongify(self)

    return [self fetchData2:dataResult];

}];

RACCommand篇:

一般用于:1:button点击 2:包装网络请求接口

一: RACCommand的创建有两种形式:

- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock; 

- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock;

注意:

1.伴随着command一起构建的signal,记得要在操作完成后发送完成消息以表示其执行完了,[subscriber sendCompleted];否则不能再执行此command。

2.UIButton中有属性rac_command用于绑定一个已经创建好的command,当使用第二种方式创建command时,button的enable属性会随command的可执行性而改变,意思是当传递布尔事件的信号传递了真值事件,按钮才可使用。另外,当你按下按钮,command开始执行时,按钮的enable被自动设置成了NO,除非command执行完了。

3.当button的rac_command已经绑定了某个command,而这个command又是以第二种方式初始化,那么你就不能动态改变button的enable,如:RAC(self.button, enable) = someSignal;这样子运行起来会报错。

二:执行RACCommand:

- (RACSignal *)execute:(id)input;

三:订阅RACCommand:

[[[command executionSignals] switchToLatest]

subscribeNext:^(id x) {

    // TODO

}];

四:在对command进行错误处理的时候,不使用subscribeError:对command的executionSignals进行错误的订阅,executionSignals这个信号是不会发送error事件的,当command包裹的信号发送error事件时,用到command的一个属性:errors,可以对错误进行订阅:

[command.errors

subscribeNext:^(NSError *x) {

    //TODO

}];

也可以通过executing属性判断是否正在执行

注意事项篇:

1.RACSignal *signalReplay = signal.replay; 

实现多个订阅者没有副作用的效果 

2.RACSubject和RACReplaySubject的区别

RACSubject必须要先订阅信号之后才能发送信号,而RACReplaySubject可以先发送信号后订阅

3.避免副作用效果处理(RACMulticastConnection)

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) { 

    NSLog(@"发送请求"); 

    [subscriber sendNext:@"ws"]; 

    return nil; 

}]; 

RACMulticastConnection *connection = [signal publish]; 

[connection.signal subscribeNext:^(id x) { 

    NSLog(@"%@", x); 

}]; 

[connection.signal subscribeNext:^(id x) { 

    NSLog(@"%@", x); 

}]; 

[connection.signal subscribeNext:^(id x) { 

    NSLog(@"%@", x); 

}]; 

[connection connect];

4.RACObserve默认会含有self,所以在RAC block内使用RACObserve时一定要用@weakify(self);@strongify(self);处理,否则会导致内存泄漏

5.RACSubject被map之后 在发送next信号时一定要发送complete方法,否则会导致内存泄漏。所以不管任何场景下都要sendComplete/sendError

6.ViewModel里用来保存数据的数组,不能使用NSMutableArray。原因是RAC是基于KVO的,而NSMutableArray的Add和Remove方法并不会给KVO发送通知,因此对NSMutableArray进行RACObserve时,并不会达到我们想要的结果。(同理其他Mutable的也都不能用)

7.flattenmap与map的区别是: block中返回的东西不同,flattenmap返回的是signal信号。flattenMap方法,实际上是根据前一个信号传递进来的参数重新建立了一个信号,这个参数,可能会在创建信号的时候用到,也有可能根本用不到。

8.RACScheduler RAC中的队列,用GCD封装的

9.RACBehaviorSubject最重要的特性就是在订阅时,向最新的订阅者发送之前的消息,RACReplaySubject 相当于一个自带 buffer 的 RACBehaviorSubject,它可以在每次有新的订阅者订阅之后发送之前的全部消息。

10.deliverOn: 内容传递切换到制定线程中,副作用在原来线程中。

subscribeOn: 内容传递和副作用都会切换到制定线程中。

11.热信号是主动的,即使你没有订阅事件,它仍然会时刻推送。而冷信号是被动的,只有当你订阅的时候,它才会发送消息。热信号可以有多个订阅者,是一对多,而冷信号只能一对一,当有不同的订阅者,消息会从新完整发送。

替换原生方法:

1.NSData

rac_readContentsOfURL: options: scheduler: 比oc多出线程设置

2.NSDictionary

rac_keySequence key 集合

rac_valueSequence value 集合

3.RACTuple元组

RACTuple *tuple = RACTuplePack(@1,@2,@4); 

// 宏的参数类型要和元组中元素类型一致, 右边为要解析的元组。 

RACTupleUnpack_(NSNumber *num1, NSNumber *num2, NSNumber * num3) = tuple; 

NSLog(@"%@ %@ %@", num1, num2, num3);

4.代理 

①之前都是需要通过代理监听,给红色View添加一个代理属性,点击按钮的时候,通知代理做事情 

rac_signalForSelector:把调用某个对象的方法的信息转换成信号,就要调用这个方法,就会发送信号。 

这里表示只要redV调用btnClick:就会发出信号,订阅就好了。

[[redV rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) { 

    NSLog(@"点击红色按钮"); 

}];

[[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {

    //TODO

}];

eg:

@weakify(self)

self.proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextFieldDelegate)];

[[self.proxy rac_signalForSelector:@selector(textFieldShouldReturn:)]

subscribeNext:^(id x) {

    @strongify(self)

}];

self.nameText.delegate = (id)self.proxy;

5.KVO

[[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) { 

    NSLog(@"%@",x); 

}];

②RACObserve(<#TARGET#>, <#KEYPATH#>)

6.监听事件

[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { 

    NSLog(@"按钮被点击了"); 

}];

7.通知

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) { 

    NSLog(@"键盘弹出"); 

}];

8.手势

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] init];

[[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {

    //TODO

}];

[self.view addGestureRecognizer:tap];

9.遍历数组

NSArray *numbers = @[@1,@2,@3,@4];

[numbers.rac_sequence.signal subscribeNext:^(id x) {

    NSLog(@"%@",x);

}];

10.遍历字典,遍历出来的键值对会包装成RACTuple

NSDictionary *dict = @{@"name":@"xmg",@"age":@18};

[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {

    // 解包元组,会把元组的值,按顺序给参数里面的变量赋值

    RACTupleUnpack(NSString *key,NSString *value) = x;

    // 相当于以下写法

    // NSString *key = x[0];

    //NSString *value = x[1];

    NSLog(@"%@ %@",key,value);

}];

双向绑定:

RAC(<#TARGET, ...#>)//单向绑定

RACChannelTo(<#TARGET, ...#>)//双向绑定

RACChannelTo(self, filmType, @(ASHRecipeFilmTypeColourNegative)) 第三个参数是指,如果值的变化中出现 nil,那么就会使用这个值来代替,相当于一个默认值。

RACChannelTo用的是RACKVOChannel实现的

eg:

RACChannelTo(self.someLabel, text) = RACChannelTo(self.viewModel, someProperty);

[self.textField.rac_newTextChannel subscribe:self.viewModel.someChannel];

[self.viewModel.someChannel subscribe:self.textField.rac_newTextChannel];

RACChannelTo(self, reviewID) = self.viewModel.someChannel;


[self.textField.rac_newTextChannel subscribe:self.anotherTextField.rac_newTextChannel];

[self.anotherTextField.rac_newTextChannel subscribe:self.textField.rac_newTextChannel];



[[RACKVOChannel alloc] initWithTarget:view keyPath:@"property" nilValue:nil][@"followingTerminal"] 

= [[RACKVOChannel alloc] initWithTarget:model keyPath:@"property" nilValue:nil][@"followingTerminal"];

与RACChannelTo(view, property) = RACChannelTo(model, property);等价

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容