跳转至

RACSignal

RACSignal:信号类,signal本身不具备发送信号的能力。

遵循RACSubscriber代理才可以发送消息。

RAC的四部曲

  1. 创建信号
  2. 订阅信号
  3. 发送信息
  4. 取消订阅
- (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];//执行订阅命令 并传入订阅者
}
  1. 创建一个订阅者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;
}
  1. 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会在订阅者发布信息的时候调用

image-20220111180953202

分页加载网络请求

#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) {
        // 处理错误

    }];
}