简体   繁体   中英

How to chain SignalProducers passing along the results

Given functions multiply() and convert() (minimal examples of the concept, I'm actually planning to query a remote server inside each function), what is a shorter way to implement multiplyAndConvert() ?

// call two async functions passing the result the from the first 
// as the argument to the second
multiplyAndConvert(3).startWithResult { val in
    print("\(val.value!)")
}

func convert(_ val: Int) -> SignalProducer<String, NSError> {
    return SignalProducer<String, NSError> { observer, _ in
        observer.send(value: String(val))
        observer.sendCompleted()
    }
}

func multiply(_ val: Int) -> SignalProducer<Int, NSError> {
    return SignalProducer<Int,NSError> { observer, _ in
        observer.send(value: val * 2)
        observer.sendCompleted()
    }
}

func multiplyAndConvert(_ val: Int) -> SignalProducer<String, NSError> {
    return SignalProducer<String, NSError> { observer, _ in
        multiply(val).startWithResult { res2 in
            switch res2 {
                case .success(let val2):
                    convert(val2).startWithResult { res3 in
                        switch res3 {
                            case .success(let val3):
                                observer.send(value:val3)
                                observer.sendCompleted()
                            case .failure(let err):
                                observer.send(error:err)
                        }
                    }
                case .failure(let err):
                    observer.send(error: err)
            }
            observer.sendCompleted()
        }
    }
}

I know there has to be a more elegant way to do this, but I'm stumped as to what it is. I've played around with map, flatMap, flatten, and most other functions but can't find a better solution.

Use flatMap:

func multiplyAndConvert(_ val: Int) -> SignalProducer<String, NSError> {
  return multiply(val).flatMap(.concat) { multipliedVal in
    return convert(multipliedVal)
  }
}

you can also pass convert directly as the second arg to flatMap rather than giving it a closure, since it is already the right type ( Int -> SignalProducer<String, NSError> )

multiply(val).flatMap(.concat, transform: convert)

but if the convert function references self in your expanded code this can result in retain cycles, in which case you would need a pass a closure capturing [weak self]

Explanation

what the flatMap does here is takes your multiply signal:

-----.value(multipliedValue)-.completed

and maps it into a signal-of-signals using the supplied closure:

    .value(convertedMultipliedValue)
    /
----x-.completed

and then "flattens" this signal-of-signals (using .Concat flattening strategy, which flattens the signal-of-signals by concatenating all the child signals- but that doesn't matter here because we are only flattening a single child signal) to give us:

----.value(convertedMultipliedValue)-.completed

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM