4

I have created two signal: getConnection and connection.rac_delete(). connection.rac_delete() depends on getConnection completing successfully.

What would be the ReactiveCocoa way of doing this? I currently have this solution but it doesn't feel like the right way.

getConnection().subscribeNext({
  let connection = $0 as! Connection

  connection.rac_delete().subscribeNext({ success in
    println("DELETED!")
  }, error: { error in
    println("ERROR DELETING!")
  })

}, error: { error in
  println("ERROR GETTING!")
})
Kyle Decot
  • 20,715
  • 39
  • 142
  • 263

2 Answers2

2

So you have a signal of connections and you want to turn its values into something else (deletions).

Normally you map signals to get new signals, but here you're mapping into another signal -- map would give you a signal of signals at this point.

But you don't really want a signal of signals, because then you have to do this annoying nested subscription business on the result:

// (pseudocode)
getConnection()
.map(connection -> connection.rac_delete())
.subscribeNext(deletionSignal ->
  deletionSignal.subscribeCompleted(->
    println("done deleting")))

That's no better than your current nested subscription -- you would like to simply flatten the signal of deletion signals into a signal of deletions, and subscribe to that directly. And that's exactly what flattenMap does!

// (pseudocode)
getConnection()
.flattenMap(connection -> connection.rac_delete())
.subscribeCompleted(->
  println("done deleting!"));

Note, though, that this behaves differently than the above code, but only when getConnection()'s signal sends more than one value. Previously, it would log for each connection that finished deleting; now it will log only once at the end when all deletions complete.

Since I assume the signal that getConnection() returns only sends one value, they'll probably behave the same in practice, but it's worth being aware of.

I'm using subscribeCompleted here instead of subscribeNext because deletion seems like something that shouldn't really resolve to a value; it's just something that takes time. But that's easy to change.

Ian Henry
  • 22,255
  • 4
  • 50
  • 61
1

There's a couple of ways you could do this depending on how often you expect these signals to fire and if there's anything else going on.

But the first thing that comes to mind is -tryMap

    getConnection().tryMap { (value, error) -> AnyObject! in
        if let connection = value as? Connection {
            return connection.rac_delete()
        }
    }.subscribeError({ (error) -> Void in
        println("Error connecting or deleting: \(error)")
    }, completed: {
        println("Deleted successfully")
    })

See, the thing you want to do is build up your signals using other signal and filters until you have the entire chain and only then do you add a subscriber.

Chris Morse
  • 326
  • 1
  • 9