问题
I have the following setup, a GridView
that consists of GridViewCell
s.
GridView
class GridView : UIView {
var gridViewCells: [GridViewCell] = []
let tapHandler: Position -> ()
init(frame: CGRect, tapHandler: Position -> ()) {
self.tapHandler = tapHandler
super.init(frame: frame)
self.gridViewCells = createCells(self)
addCellsToView(self.gridViewCells)
}
func addCellsToView(cells: [GridViewCell]) {
for cell in cells {
self.addSubview(cell)
}
}
}
GridViewCell
class GridViewCell: UIImageView {
let position: Position
let tapHandler: Position -> ()
init(frame: CGRect, position: Position, tapHandler: Position -> ()) {
self.position = position
self.tapHandler = tapHandler
super.init(frame: frame)
}
func handleTap(sender: UITapGestureRecognizer) {
self.tapHandler(self.position)
}
}
Note that I omitted some less relevant parts of the code, just know that when creating the cells in createCells()
, every cell gets a UITapGestureRecognizer
that targets handleTap:
, I am also using:
typealias Position = (Int, Int)
So, as you can see, whenever a GridView
gets instantiated, it gets passed a callback function tapHandler: Position -> ()
that ultimately gets called by the cell when a cell is tapped by the user.
Now, I want to turn the tap events into a RAC Signal
. I have no clue how to approach this, as I am very new to RAC. Thanks to Colin Eberhardts blog articles, I managed to get a basic understanding of the building blocks and implement a custom signal like so:
func createSignal() -> Signal<String, NoError> {
var count = 0
return Signal {
sink in
NSTimer.schedule(repeatInterval: 1.0) { timer in
sink.sendNext("tick #\(count++)")
}
return nil
}
}
I now basically want a similar behaviour only that the emitted events aren't triggered by a NSTimer
, but rather by the handleTap()
function.
回答1:
You can accomplish this by using Signal.pipe()
. This gives you a tuple with both the signal
, and the observer
tied to that signal:
let (signal, observer) = Signal<String, NoError>.pipe()
You can use that the same way you used sink
in your example (note that sink
is just the old terminology for observer
:))
In the case of buttons or gesture recognizers though, you can leverage the RAC 2
extensions. For example:
let signal: SignalProducer<(), NoError> = gestureRecognizer
.rac_gestureSignal()
.toSignalProducer()
.mapError { fatalError("Unexpected error: \(error)"); return () } // errors cannot occur, but because they weren't typed in `RACSignal` we have to explicitly ignore them.
.map { _ in () }
Or UIControl.rac_signalForControlEvents
.
I published a gist with extensions to simplify some of these common operations. I hope that's useful!
来源:https://stackoverflow.com/questions/34167555/how-to-create-custom-signal-in-reactivecocoa-4