Mark Lilback
Mark Lilback

Reputation: 1164

generically injecting a side effect in a SignalProducer

My app has a status area at the top that shows progress information (similar to Xcode and iTunes). I want to update it by injecting side effects into an event stream, using a closure that converts the stream's value into the ProgressUpdate value. I'm using an extension on SignalProducer so any signal producer in my app can update the app's status area (there is a lot more involved to allow for multiple signals at once, but that doesn't affect this problem).

I'm basing it on SignalProducer's on(starting:, started:, ...). It requires the latest swift 3.1 beta to allow the constraint on the error type, but this is straight from a playground.

import ReactiveSwift

struct Rc2Error: Error {
}

struct ProgressUpdate {
    let message: String
    let value: Double = -1
}

class MacAppStatus {
    fileprivate func process(event: (Event<ProgressUpdate, Rc2Error>) -> Void) 
    {
        //update UI based on the event
    }
}


extension SignalProducer where Error == Rc2Error {
    func updateProgress<Value>(status: MacAppStatus, converter: @escaping (Value) -> ProgressUpdate) -> SignalProducer<Value, Error>
    {
        return SignalProducer<Value, Error> { observer, compositeDisposable in
            self.startWithSignal { signal, disposable in
                compositeDisposable += disposable
                compositeDisposable += signal
                    .on(event: { (orignal) in
                        switch original {
                        case .completed:
                            status.process(Event<ProgressUpdate, Rc2Error>.completed)
                        case .interrupted:
                            status.process(Event<ProgressUpdate, Rc2Error>.interrupted)
                        case .failed(let err):
                            status.process(Event<ProgressUpdate, Rc2Error>.failed(err))
                        case .value(let val):
                            status.process(Event<ProgressUpdate, Rc2Error>.value(converter(val)))
                        }
                    })
                    .observe(observer)
            }
        }
    }
}

```

The last line of .observe(observer) produces an error:

error: cannot convert value of type 'Observer<Value, Rc2Error>' to expected argument type 'Observer<_, Rc2Error>'

Any ideas why this conversion fails? Suggestions on a different way to accomplish this?

Upvotes: 0

Views: 439

Answers (1)

Mark Lilback
Mark Lilback

Reputation: 1164

It looks like it was just bad error reporting from the compiler. The actual problem was that process() should take an Event, not a closure that takes an event. It also needed an empty external parameter name.

Changing the signature to

    fileprivate func process(_ event: Event<ProgressUpdate, Rc2Error>) 

and fixing the original typo Mike Taverne pointed out fixed it.

Upvotes: 0

Related Questions