Nacho offered me a little bit of help today with a relatively simple problem. Here are some notes on it for future reference.
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.
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 }
})
}
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
}
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!
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)