iOS开发RAC的函数式编程

释放双眼,带上耳机,听听看~!

为什么是函数式

  • 数据与函数是松耦合的
  • 函数隐藏了它们的实现,语言的抽象是函数,以及将函数组合起来表达。
  • 核心抽象模型是函数,不是数据结构
  • 核心活动是编写新的函数。
  • 变量缺省是不变的,减少可变性变量的使用,并发性好

函数式的实现

objc语言使用block实现函数式编程,在典型的函数式编程框架RAC中,把数据的生成和数据的处理单独的放在block中处理,数据的生产和消费之间是松耦合的,block是数据处理的最小单位。

本文使用的是Objc版本的ReactiveCocoa,创建一个Objc的项目,使用pod导入:

pod 'ReactiveObjC', '3.0.0'

创建RACSignal以及订阅这个RACSignal接收消息

简单的代码如下

RACSignal* signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@"message"];
return nil;
}];
[signal subscribeNext:^(id  _Nullable x) {
NSLog(@"received:%@", x);
}];
// 控制台输出
2017-04-24 17:36:49.364 EffectiveOCDemo[46385:2426010] received:message

RACSignal对象创建

// RACSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
// RACDynamicSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}

使用RACSignal类的类方法createSignal创建一个RACSignal最终创建的是一个RACSignal的子类RACDynamicSignal的对象,对象中会把参数中的didSubscribe block 保存到_didSubscribe实例变量中,后面发送消息的时候回用到_didSubscribe这个block。

subscribeNext 方法

// RACSignal.m
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
// RACSubscriber.m 快捷方法创建RACSubscriber对象
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
RACSubscriber *subscriber = [[self alloc] init];
subscriber->_next = [next copy];
subscriber->_error = [error copy];
subscriber->_completed = [completed copy];
return subscriber;
}
// RACDynamicSignal.m
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}

RACSignal的subscribeNext方法中会创建了一个sub,_next成员变量用于保存参数中的nextBlock,后面接收消息的时候会用到_next block。创建了RACSubscriber对象之后,调用RACDynamicSignal对象的的subscribe方法,并且把RACSubscriber对象当做参数进行传递。然后执行之前保存的didSubscribe block

self.didSubscribe(subscriber);

也就是执行了下面这个block,在这个block中又会执行RACSubscriber的sendNext方法

RACSignal* signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@"message"];
return nil;
}];

sendNext方法

- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}

sendNext方法会同步取出之前保存的next block,然后执行该block,并且传递sendNext方法中的参数,执行nextblock也就是执行了下面这个block

[signal subscribeNext:^(id  _Nullable x) {
NSLog(@"received:%@", x);
}];

这样一个完整的消息发送接收链就创建起来了,在RACSignal createSignal block中发送的数据在signal subscribeNext block中可以同步的接收到。

小结

冷信号和热信号
RACSignal* signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
[subscriber sendNext:@"message"];
return nil;
}];

创建的RACSignal对象里面的didSubscribe并不会自动执行,这种RACSignal成为冷信号,当且仅当调用了subscribeNext订阅这个信号,RACSignal对象 的didSubscribe才会得到执行,这样RACSignal成为了热信号,在_didSubscribe block执行的时候同时会调用RACSubscriber sendNext方法,sendNext又会调用RACSubscriber的nextBlock,这样消息转发完毕。

RACSignal数据流图
RACSignal数据流图

人已赞赏
iOS文章

iOS KVO 中 runtime 探究

2020-4-28 2:16:49

iOS文章

iOS发布自己的CocoaPods库

2020-4-28 3:31:48

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索