Create a signal that emits one object then completes?

1.6k Views Asked by At

With RxSwift, I would do Observable.just(1) which will emit 1 then emit completed.

It looks like with RAC2 you could do: [RACSignal return:@1]

How do I do that with RAC3?

To be more clear... I'm looking for a way to create a RAC3 Signal that produces a single hard-coded value. How would I do that? (SignalProducer(value: 1) doesn't work that way.)

2

There are 2 best solutions below

0
On BEST ANSWER

After reading the discussion, I think the answer by Charlotte Tortorella stands correct: you achieve the required behavior with SignalProducer(value: 1).

I think the problem is a miss understanding about what Signal and SignalProducer are.

As described here, a Signal in ReactiveSwift is a hot RACSignal in RAC 2.0 or Observable in Rx, and a SignalProducer in ReactiveSwift is a cold RACSignal in RAC 2.0 or Observable in Rx. This is deliberate deviation from other reactive frameworks as well as from RAC < 3.0.

This means, you most likely have a method that takes a cold RACSignal or Observable since you want it to fire for every subscriber.

So if you want to convert your RAC 2.0 code, that expects a cold Signal or Observable, you will need to change it to take a SignalProducer in RAC >= 3.0.

As an illustration take this example in ObjC and RAC 2.0:

-(void)observeSignal:(RACSignal *)signal
{
    [signal subscribeNext:^(NSNumber *x) {
        NSLog(@"Next: %@", x);
    } completed:^{
        NSLog(@"Completed");
    }];
}

Calling this method like this

RACSignal *signal = [RACSignal return:@(1)];
[self observeSignal:signal];
[self observeSignal:signal];

(twice for illustration of the behaviour on each subscription) will print

Next: 1
Completed
Next: 1
Completed

In Swift and with ReactiveCocoa 5.0, an equivalent implementation could look like this

func observe(produer: SignalProducer<Int, NoError>) {
    produer.start { event in
        switch event {
        case .value(let value):
            print("Next: \(value)")
        case .completed:
            print("Completed")
        default:
            break
        }
    }
}

Called like this

let producer = SignalProducer<Int, NoError>(value: 1)
observe(produer: producer)
observe(produer: producer)

it produces the same output

Next: 1
Completed
Next: 1
Completed

The swift version might look a bit bulkier, but if you only need the Next/value Events they look more or less the same. Note, that you'll need to start the producer instead of just observe the signal.

So in conclusion:

You are correct, theres no way to provide an equivalent if you expect a Signal. For an equivalent implementation, you will need to change your function to take a SignalProducer. SignalProducer is equivalent to a cold Signal which will fire for each subscriber.

6
On

RAC 3 and up uses a constructor.

SignalProducer(value: 1)