一 升阶和降阶
二
1.创造高阶信号
(1)RACSignal
*signal = [
RACSignal
return
:
@1
];
RACSignal
*signalHighOrder = [
RACSignal
return
:signal];
(2)RACSignal
*anotherSignal = [signal
map
:^
id
(
id
value) {
return
[
RACSignal
return
:value];
}];
2.订阅高阶信号
RACSignal
*signal =
@[@1
,
@2
,
@3]
.
rac_sequence
.
signal
;
RACSignal
*highOrderSignal = [signal
map
:^
id
(
id
value) {
return
[
RACSignal
return
:value];
}];
[highOrderSignal
subscribeNext
:^(
RACSignal
*aSignal) {
[aSignal
subscribeNext
:^(
id
x) {
// get real value here.
}]; }];
三 降阶操作
1.SwitchToLatests
信号1 信号2(将信号1关闭) 信号4 信号5与高阶信号 信号6 信号7 判断信号是否结束
示例一
RACSignal
*autoRunButtonClickSignal = [
self
.autoRunBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
RACSignal
*oneStepButtonClickSignal = [
self
.oneStepBtn
rac_signalForControlEvents:UIControlEventTouchUpInside];
RACSignal
*idSignal = [
RACSignal
return
:
nil
];
RACSignal
*timerSignal = [
RACSignal
interval
:
1
onScheduler
:[
RACScheduler
mainThreadScheduler
]];
autoRunButtonClickSignal = [autoRunButtonClickSignal
mapReplace
:idSignal];
oneStepButtonClickSignal = [oneStepButtonClickSignal
mapReplace
:timerSignal];
RACSignal
*controlSignal = [autoRunButtonClickSignal
merge
:
oneStepButtonClickSignal];
controlSignal = [controlSignal
switchToLatest
];
示例二 搜索请求
网络差 连续发送不同的请求 有时后搜索的会先返回 造成搜索不准
RACSignal
*searchTextSignal = [
self
.searchTextField rac_textSignal];
RACSignal
*requestSignals = [searchTextSignal
map
:^
id
(
NSString
*searchText) {
NSString
*urlString = [
NSString
stringWithFormat
:
@"http://xxxx.xxx.xxx/?q=%@"
, searchText];
NSURL
*url = [
NSURL
URLWithString
:urlString];
NSURLRequest
*request = [
NSURLRequest
requestWithURL
:url];
return
[
NSURLConnection
rac_sendAsynchronousRequest
:request];
}];
//第二个信号去请求时会把第一个信号关掉
requestSignals = [requestSignals
switchToLatest
];
2.If/then/else
If/then/
else
本质
&
类似操作
+ (
RACSignal
*)
if
:(
RACSignal
*)boolSignal
then:(
RACSignal
*)trueSignal
else
:(
RACSignal
*)falseSignal {
return
[[boolSignal
map
:^(
NSNumber
*value) {
return
(value.
boolValue
? trueSignal : falseSignal);
}]
switchToLatest
];
}
+ (
RACSignal
*)
switch
:(
RACSignal
*)signal
cases:(
NSDictionary
*)cases
default
:(
RACSignal
*)defaultSignal;
3.Flatten 不会丢数据 扁平
异步 并发 同时允许2段并发(此时已经满了,黄色和绿色信号) 绿色信号或黄色信号结束了橙色信号才会开始
Flatten:
1
的思考
-
返回 a 信号,b 信号的高阶信号 flatten:1 相当于 a信号concat:b信号
- (RACSignal *)concat;
concat 与1秒延迟信号
RACSignal *signal = @[@1, @3, @7,
@9, @8].rac_sequence.signal;
RACSignal *timerSignal = [[signal map:^id(id value) {
return [[RACSignal return:value] delay:1];
}] concat];
降阶操作总结
SwitchToLatests (将上一个信号抛弃)
Flatten (Merge)
Concat (Flatten:1)
四 思考
1.改变某个值的个数
返回的是1,2,2,3,3,3
RACSignal *signal = @[@1, @2, @3].rac_sequence.signal;
RACSignal *mappedSignal = [[signal map:^id(NSNumber *value) {
return [[[RACSignal return:value] repeat] take:value.integerValue];
}] flatten];
2.将一个值改为一个错误
RACSignal
*signal =
@[@1
,
@2
,
@3
,
@0]
.
rac_sequence
.
signal
;
RACSignal
*mappedSignal = [[signal map:^
id
(NSNumber *value) {
if
(value.integerValue ==
0
) {
return
[RACSignal error:[NSError errorWithDomain:
@"0"
code:
0
}
else
{
return
[RACSignal
return
:value];
}
}] flatten];
3.改变值的时间间隔
RACSignal
*signal =
@[
@"♪5"
,
@"♬1"
,
@"♬2"
,
@"♬3"
,
@"♩4"
]
.
rac_sequence
.
signal
;
NSDictionary
*toneLengthMap =
@{
@"♩"
:
@0.5
,
@"♪"
:
@0.25
,
@"♬"
:
@0.125}
;
RACSignal
*mappedSignal = [[signal
map
:^
id
(
NSString
*value) {
NSString
*tone = [value
substringFromIndex
:
1
];
NSString
*length = [value
substringToIndex
:
1
];
NSNumber
*toneValue =
@(
tone.
integerValue
)
;
NSNumber
*toneLength = toneLengthMap[length];
return
[[
RACSignal
return
:toneValue]
concat
:[[
RACSignal
empty
]
delay
: toneLength.
doubleValue
]];
}]
concat
];
delay 是不靠谱的(concat一个 empty 信号,delay 延长)
4.Map
————>Flatten FlattenMap 高阶
—
>降阶
五 FlattenMap
1.重要性
可以用 FlattenMap 实现很多的信号转换
支持串行异步操作(类似 Promise)
满足 Monad 部分定义 (bind 和 return 才完全满足)
FlattenMap要求传入信号,然后返回扁平化后的 value
RACSignal
*flatten = [signal flattenMap:^RACStream *(RACSignal *value) {
return
value;
}];
RACSignal
*map = [signal flattenMap:^RACStream *(
id
value) {
id
anotherValue = value;
// map here!
return
[RACSignal
return
: anotherValue];
}];
过滤掉空的值
RACSignal
*filter = [signal flattenMap:^RACStream *(
id
value) {
BOOL
filter = (value ==
nil
);
// filter here!
return
filter ? [RACSignal empty] : [RACSignal
return
:value];
}];
在实际使用时的重要场景
RACSignal
*getSignal = [signal
flattenMap
: ^
RACStream
*(
NSString
*url) {
NSURLRequest
*request = [
NSURLRequest
requestWithURL
:[
NSURL
URLWithString
:url]];
return
[
NSURLConnection
rac_sendAsynchronousRequest
:request];
}];
RACSignal
*jsonSignal = [getSignal
flattenMap
: ^
RACStream
*(
NSData
*data) {
NSError
*error =
nil
;
id
result = [
NSJSONSerialization
JSONObjectWithData
:data
options
:
0
error
:&error];
return
error ==
nil
? [
RACSignal
return
:result]: [
RACSignal
error
: error];
}];
RACSignal
*getItemSignal = [jsonSignal
flattenMap
: ^
RACStream
*(
NSDictionary
*value) {
if
(![value
isKindOfClass
:[
NSDictionary
class
]] || value[
@"data.url"
] ==
nil
) {
return
[RACSignal error:someError];
}
NSURLRequest
*anotherRequest = [
NSURLRequest
requestWithURL
:
[
NSURL
URLWithString
:value[
@"data.url"
]]];
return
[
NSURLConnection
rac_sendAsynchronousRequest
:anotherRequest];
}];
2.FlattenMap 与 monad,bind
- Functor,Applicative,Monad 概念
- FlattenMap 符合 Monad 的 bind 定义,但是无法实现 takeUntil:操作,无法做副作用操作例如 take:的计数
- (
instancetype
)flattenMap:(RACStream * (^)(
id
value))block;
- (
instancetype
)bind:(RACStreamBindBlock (^)(
void
))block;
typedef
RACStream
* (^RACStreamBindBlock)(
id
value,
BOOL
*stop);
3.bind妙用
- (
RACSignal
*)take:(
NSUInteger
)count {
if
(count ==
0
)
return
[
RACSignal
empty
];
return
[
self
bind:^{
__block
NSUInteger taken =
0
;
return
^
id
(
id
value,
BOOL
*stop) {
if
(taken < count) {
++taken;
if
(taken == count) *stop =
YES
;
return
[class
return
:value];
}
else
{
return
nil
; }
}; }];
}
4.bind简单实现和问题
- (
RACSignal
*)bind:(
RACStreamBindBlock
(^)(
void
))block;
{
return
[
RACSignal
createSignal
:^
RACDisposable
*(
id
<
RACSubscriber
> subscriber) {
RACStreamBindBlock
bindBlock = block();
[
self
subscribeNext:^(
id
x) {
BOOL
stop =
NO
;
RACSignal *signal = (RACSignal *)bindBlock(x, &stop);
if
(signal ==
nil
|| stop) { [subscriber sendCompleted];
}
else
{
[signal subscribeNext:^(
id
x) { [subscriber sendNext:x];
} error:^(NSError *error) { [subscriber sendError:error];
} completed:^{ }];
}
} error:^(NSError *error) { [subscriber sendError:error];
} completed:^{ [subscriber sendCompleted]; }];
return
nil
;
}]; }
六 有用的高阶操作
- (RACSignal *)try:(
BOOL
(^)(
id
value, NSError **errorPtr))tryBlock; 对每个值进行分析,用来简化 flattenMap 等操作
- (
RACSignal
*)tryMap:(
id
(^)(
id
value, NSError **errorPtr))mapBlock;
- (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock;
- (
RACSignal
*)catchTo:(
RACSignal
*)signal;
- (RACSignal *)timeout:(
NSTimeInterval
)interval
onScheduler:(RACScheduler *)scheduler;
七 扩展问题
不能 信号是 pushDriver 只能被动接收 浓缩信号变短(冷热信号操作)