Deprecation warning says nothing to me - Use properties instead. 'buffer' will be removed in RAC 5.0
What properties? Could someone provide clear example. Thanks.
buffer(0)
Signal.pipe
, but less efficient.buffer(1)
MutableProperty
without the guarantee of always having a current value at compile time. That's why we recommend properties over buffer(1)
in the deprecation message.buffer(n)
for n > 1SignalProducer.replayLazily
as the replacement, albeit the semantics being a bit different.@andersio oh, thanks a lot, I thought not about _right_ properties
Hy,
What if I wanted to send back an error to the buffered SignalProducer?
In the MutableProperty there is NoError in the Signal or SignalProducer
Regards
If you really need the old buffer
semantics, you may create a Signal
pipe, wrap it with a SignalProducer
and use replayLazily
.
Note that replayLazily
starts caching events only if it has ever been started.
let (signal, observer) = Signal<Int, TestError>.pipe()
let replayedProducer = SignalProducer(signal: signal).replayLazily(1)
// Start the buffering immediately.
replayedProducer.start()
Thanks, It's what I was looking for
Thanks,
replayLazily seems has side effect.
take a look at example below
let (signal, observer) = Signal<Int, NSError>.pipe()
let replayedProducer = SignalProducer(signal: signal).replayLazily(1)
// Start the buffering immediately.
replayedProducer.start()
func someAsyncProcedure() {
observer.send(error: NSError()) //<------------ LINE 2
}
func someProcedure {
replayedProducer.startWithResult {
switch($0) {
case .success(let value):
print(value)
case .failure(let error):
print(error) //<------------ LINE 1
}
}
someAsyncProcedure()
}
someProcedure() //everything is fine
someProcedure() //LINE 1 is called before LINE 2
I didn't read the code of replayLazily, but it seems used a cached value instead of using observer sent value. Problem is when observer send value, the failure procedure is called instead of success.
To solve this problem I have to create a Signal every time I call someProcedure, don't think it's a good practice... any comment is welcome
When the second time you call someProcedure
, the underlying producer has already terminated with the error you sent in the first time you call someProcedure
(with someAsyncProcedure
).
The replayed producer cached this error for you, and this is why you get "Line 1" called before "Line 2" - it replayed the error.
Please note that sending an error means termination of the event stream.
@andersio Thanks for replying.
I guess since the producer is terminated, it's OK to create a new signal to handle the async procedure like this
class SomeClass {
private var observer: Observer<String, NSError>!
//delegate method async called from other thread
func someAsyncProcedure() {
observer.send(error: NSError()) //<------------ LINE 2
}
func someProcedure -> SignalProducer<String, NSError> {
let producer SignalProducer<String, NSError> { [weak self] sink, _ in
self!.observer = sink
}
return producer
}
}
func xxx() {
SomeClass.someProcedure().startWithResult {
switch($0) {
case .success(let value):
print(value)
case .failure(let error):
print(error) //<------------ LINE 1
}
}
}
xxx()
xxx()
I guess what I want is Future semantics here...
I've read #2744 and noticed
PropertyType has the exact same semantics as SignalProducer.buffer
But as benji-bou said, Property does not emit errors. It seems I have to use two Property to handle error, one is Success Property, wrapping the value I want, the other is an Error Property, and I have to observe on both of them, right?
It seems what you want is wrapping a delegate pattern as streams of values, while the delegate is triggered as a result of starting the producer.
In this case, I think you'd be better off with an internal Signal<Result<Value, Error>, NoError>
signal, and pipe your delegate callback results into it. Then you may derive producers from it.
let asyncResult: Signal<Result<Value, Error>, NoError>
func work() -> SignalProducer<Value, Error> { observer, disposable in
// Mutual exclusion via semaphore or queues, if necessary.
disposable += asyncResult.observeValues { result in
switch result {
case let .success(value):
observer.send(value: value)
observer.sendCompleted()
case let .failure(error):
observer.send(error: error)
}
}
startTheAsyncWorkThatCallbacksViaDelegate()
}
@andersio Thanks for your patience, problem solved 👍
Most helpful comment
If you really need the old
buffer
semantics, you may create aSignal
pipe, wrap it with aSignalProducer
and usereplayLazily
.Note that
replayLazily
starts caching events only if it has ever been started.