Skip to content

Instantly share code, notes, and snippets.

@jbrennan jbrennan/signals.md
Created Nov 16, 2015

Embed
What would you like to do?
Some notes on getting help with Reactive Cocoa Signals with help from a coworker

Notes about Signals

Nacho offered me a little bit of help today with a relatively simple problem. Here are some notes on it for future reference.

The problem

I have a container view which has in it a TabBarView and a ScrollView. When one of the tabs in the tab bar view is tapped, I want it to update its internal state (which button is selected) and then I need the container view to be able to respond as well (to scroll its scrollview).

RAC and Signals still feel totally alien to me, but this seemed like a good example to at least learn how I'd do this pattern.

The property

We first started by adding a tabChanges property, which is a Signal emitting Int and no error.

var tabChanges: Signal<Int, NoError> {

The next step was to enumerate() all the tabs (which is [UIButton]) and map that array:

	tabs.enumerate().map { (index, tab) in

For each of those buttons, we return a Signal from the control event of the button, which is mapped to return the given index of the tab whose control signals we're mapping:

		return tab.signalForControlEvents(.TouchUpInside).map { index }

The tabs.enumerate().map { ... } call above returns an array of Signal. What we want though, is a steady, flat stream of signals, so we merge that array into a new signal. All together, it looks like:

var tabChanges: Signal<Int, NoError> {
	return Signal.mergeSignals(tabs.enumerate().map { (index, tab)  in
		return tab.signalForControlEvents(.TouchUpInside)
			.map { index }
		})
}

Using the property internally

But wait! I still want to use this signal internally so I can update stuff about which tab is selected. So, in init I need to observeNext on the signal.

First I need to takeUntilObjectDeallocates(self) so I'm explicit about object ownership (kind of shitty to foist memory management back on the programmer in 2015).

self.tabChanges.takeUntilObjectDeallocates(self)

Then I need to observeNext and do my business there. Altogether it looks like:

self.tabChanges.takeUntilObjectDeallocates(self)
	.observeNext{ [unowned self] in
		self.selectedIndex = $0 // or, the int value of the signal
	}

Conclusion

This was helpful to see a simple example illustrated! So big thanks to Nacho for this! I'm hoping these notes will be a little case study for myself (and maybe others) going forward.

On the other side though, I can't help but feel like this all seems like jibberish to me still. Line by line, I get what the code does, it just seems like such a strange way to solve this problem. Most of these lines feel like a justification, not like they're actively accomplishing my goal.

The terminology is still confusing (a Signal sounds more like a "pipe" or a "wire" than a thing that is transmitted by a wire, which is what a signal sounds like to me).

Anyway, I'm holding out hope, and I know my opinion on this is unpopular on our team (and in the Cocoa community these days), but alas, it's how I'm still feeling!

Onward!

@ka-interview

This comment has been minimized.

Copy link

ka-interview commented Nov 16, 2015

Yes, this is exactly the archetypal family in which I suspect that traditional target/action paradigms offers significantly better abstraction-cost-versus-benefit. :/

(whoops, this was Andy, commenting while logged into the wrong account)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.