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

时间:2015-12-08 22:48:33

标签: ios swift reactive-cocoa

我有以下设置,GridViewGridViewCell 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)
    }    
}

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

typealias Position = (Int, Int)

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

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

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

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

1 个答案:

答案 0 :(得分:8)

您可以使用Signal.pipe()来完成此操作。这会为您提供一个元组,signalobserver与该信号相关联:

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

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

如果是按钮或手势识别器,您可以使用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 () }

UIControl.rac_signalForControlEvents

我发布了a gist扩展,以简化其中一些常见操作。我希望这很有用!