Skip to content

Instantly share code, notes, and snippets.

@jbrennan
Created November 16, 2015 21:02
Show Gist options
  • Save jbrennan/e7a9dac0cee086ceb662 to your computer and use it in GitHub Desktop.
Save jbrennan/e7a9dac0cee086ceb662 to your computer and use it in GitHub Desktop.
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
Copy link

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