RACSignal¶
RACSignal:信号类,signal本身不具备发送信号的能力。
遵循RACSubscriber代理才可以发送消息。
RAC的四部曲¶
- 创建信号
- 订阅信号
- 发送信息
- 取消订阅
- (void)RACSignalTest {
//1、创建信号量
RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"创建信号量");
//3、发布信息
[subscriber sendNext:@"I'm send next data"];
//3.1发送完成信号,并取消订阅
[subscriber sendCompleted];
self.subscriber = subscriber;
NSLog(@"那我啥时候运行");
//4用于取消订阅时清理资源用,比如释放一些资源
return [RACDisposable disposableWithBlock:^{
NSLog(@"RACDisposable");
}];
}];
//2、订阅信号量
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//主动触发取消订阅
[disposable dispose];
//2.2订阅错误信号
[signal subscribeError:^(NSError * _Nullable error) {
NSLog(@"error");
}];
//2.3订阅完成信号
[signal subscribeCompleted:^{
NSLog(@"completed");
}];
}
创建信号¶
创建一个Signal信号对象,传递的参数是一个block。block的返回值是RACDisposable
对象,block的参数是遵循RACSubscriber协议
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
可以看到其内部创建了一个RACDynamicSignal
信号,并且把didSubscribe
这个block也传了过去
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];//保存
return [signal setNameWithFormat:@"+createSignal:"];
}
创建了一个 RACDynamicSignal
类型的信号,然后将传入的名为 didSubscribe
的block保存在创建的信号的 didSubscribe
属性中,此时仅仅是保存并未触发。返回RACDynamicSignal
这个对象。
创建信号本质就是创建了一个 RACDynamicSignal
类型的信号,并将传入的代码块保存起来,留待以后调用。
但是这个block什么时候调用呢?¶
没错就是在我们订阅信号的时候调用
订阅信号¶
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
这里一订阅信号就给我一个block,并且还带一个参数x,并不知道是个什么东西,就先打印出来。 然后我们点击进去看下内部实现
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];//执行订阅命令 并传入订阅者
}
- 创建一个订阅者RACSubscriber
RACSubscriber订阅者有三个block:nextBlock,errorBlock,completeBlock
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
RACSubscriber *subscriber = [[self alloc] init];
//保存了nextblock
subscriber->_next = [next copy];
subscriber->_error = [error copy];
subscriber->_completed = [completed copy];
return subscriber;
}
- RACDynamicSignal调用
subscribe
方法
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
//销毁
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
//RACPassthroughSubscriber才是真正的订阅者,保存subscriber self dispose。
//信号signal 订阅者subscriber 销毁disposable。
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
//这里就在调用didSubscribe方法,并且把刚才传入的subscriber调用出去
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}
//在这个方法中会判断是否有didSubscriber,
//如果有就调用block并且把传入进来的subscriber作为block的参数调用出去
订阅信号之后就会运行创建信号的block,¶
这个时候我们再来看下创建信号的方法
[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"创建信号量");
//3、发布信息
[subscriber sendNext:@"I'm send next data"];
NSLog(@"那我啥时候运行");
return nil;
}];
//2、订阅信号量
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
它给我们一个subscriber
而这个sbuscriber就是我们调用订阅信号的方法所创建的subscriber,然后我们要用这个订阅者发送信息
那我们订阅的信号啥时候调用呢?¶
- 当我们的订阅者发送消息的时候就会调用。
这个时候我们看下订阅者发送信息的方法内部做了什么
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
这里的代码很简洁了 主要就是做了一件事,如果nextblock不为空就把传进来传value原封不动的调用出去。 而这个nextblock就是我们在订阅信号的时候创建的那个subscriber所保存的nextblock。
所以RACSignal的处理流程就是
- 创建信号的block会在订阅信号的时候调用
- 订阅信号的block会在订阅者发布信息的时候调用
图¶
分页加载网络请求¶
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <AFNetworking/AFNetworking.h>
// 定义接口URL
NSString *const kAPIURL = @"https://example.com/api";
// 定义每页大小和初始页索引
NSInteger const kPageSize = 10;
NSInteger const kInitialPageIndex = 1;
// 定义网络请求方法,该方法使用AFNetworking库发起网络请求,并返回一个RACSignal信号。
- (RACSignal *)fetchDataWithPageSize:(NSInteger)pageSize pageIndex:(NSInteger)pageIndex {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// 创建请求参数
NSDictionary *parameters = @{
@"pageSize" : @(pageSize),
@"pageIndex" : @(pageIndex)
};
// 发起网络请求
return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[manager GET:kAPIURL parameters:parameters progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
[subscriber sendNext:responseObject];
[subscriber sendCompleted];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[subscriber sendError:error];
}];
return nil;
}] replayLazily];
}
// 示例使用
- (void)loadData {
// 初始化页码
__block NSInteger pageIndex = kInitialPageIndex;
// 创建分页加载信号
//创建了一个loadNextPageSignal信号,通过flattenMap操作符来增加页码并发起网络请求。
RACSignal *loadNextPageSignal = [[[RACSignal empty] startWith:nil] flattenMap:^RACStream *(id value) {
// 增加页码
pageIndex++;
// 发起网络请求并返回信号
return [self fetchDataWithPageSize:kPageSize pageIndex:pageIndex];
}];
// 监听信号并处理返回结果
//使用deliverOnMainThread将信号的结果切换到主线程,并使用subscribeNext监听信号的返回结果(处理接口返回的数据并更新UI),或在error块中处理错误情况。
[[loadNextPageSignal deliverOnMainThread] subscribeNext:^(id responseObject) {
// 处理接口返回的数据
NSLog(@"Received response: %@", responseObject);
// 解析数据并更新UI
} error:^(NSError *error) {
// 处理错误
}];
}