How to create your own signal in ReactiveCocoa 4?

I have the following setup: GridView , which 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 a few less important parts of the code, I just know that when creating cells in createCells() each cell gets a UITapGestureRecognizer that targets handleTap: I also use:

 typealias Position = (Int, Int) 

So, as you can see, whenever the GridView instance receives the instance, it is passed the tapHandler: Position -> () callback function tapHandler: Position -> () , which is ultimately called by the hundredth when the cell is used by the user.

Now I want to enable tap events in the RAC Signal . I do not know how to approach this, since I am very new to RAC. Thanks to the blog article by Colin Eberhardt , I was able to get a basic idea of ​​building blocks and realize my own signal as follows:

 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 } } 

Now I basically want this behavior to be only because the emitted events were not triggered by NSTimer , but rather by the handleTap() function.

+5
source share
1 answer

You can accomplish this using Signal.pipe() . This gives you a tuple with the signal and observer binding to this signal:

 let (signal, observer) = Signal<String, NoError>.pipe() 

You can use this 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, you can use the RAC 2 extensions. For instance:

 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 posted a gist with extensions to simplify some of these common operations. Hope this is helpful!

+8
source

Source: https://habr.com/ru/post/1237698/


All Articles