如何在ReactiveCocoa 4中创建自定义信号?

时间:2022-05-14 08:12:51

I have the following setup, a GridView that consists of GridViewCells.

我有以下设置,一个由GridViewCells组成的GridView。

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:

请注意,我省略了一些不太相关的代码部分,只要知道在createCells()中创建单元格时,每个单元格都会获得一个以handleTap:为目标的UITapGestureRecognizer,我也在使用:

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.

因此,正如您所看到的,每当GridView被实例化时,它都会传递一个回调函数tapHandler:Position - >(),当用户点击一个单元格时,它最终会被单元调用。

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:

现在,我想将tap事件转换为RAC信号。我不知道如何处理这个问题,因为我对RAC很新。感谢Colin Eberhardts的博客文章,我设法对构建块有了基本的了解,并实现了这样的自定义信号:

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.

我现在基本上只想要一个类似的行为,即发出的事件不是由NSTimer触发的,而是由handleTap()函数触发的。

1 个解决方案

#1


8  

You can accomplish this by using Signal.pipe(). This gives you a tuple with both the signal, and the observer tied to that signal:

您可以使用Signal.pipe()完成此操作。这为您提供了一个元组,包含信号和与该信号相关的观察者:

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 :))

您可以像在示例中使用sink一样使用它(请注意,sink只是观察者的旧术语:))

In the case of buttons or gesture recognizers though, you can leverage the RAC 2 extensions. For example:

但是,在按钮或手势识别器的情况下,您可以利用RAC 2扩展。例如:

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!

我发布了一个带有扩展的要点,以简化这些常见操作。我希望这很有用!

#1


8  

You can accomplish this by using Signal.pipe(). This gives you a tuple with both the signal, and the observer tied to that signal:

您可以使用Signal.pipe()完成此操作。这为您提供了一个元组,包含信号和与该信号相关的观察者:

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 :))

您可以像在示例中使用sink一样使用它(请注意,sink只是观察者的旧术语:))

In the case of buttons or gesture recognizers though, you can leverage the RAC 2 extensions. For example:

但是,在按钮或手势识别器的情况下,您可以利用RAC 2扩展。例如:

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!

我发布了一个带有扩展的要点,以简化这些常见操作。我希望这很有用!