ReactiveCocoa 4的简单UIGestureRecogniser示例



努力让一个简单的ReactiveCocoa 4示例发挥作用。

  • 我的层次结构中有一个视图的平移手势识别器
  • 我有一个用于触摸事件的目标类(假设我想根据触摸位置生成网络数据包)

因此,我似乎想从我的手势识别器创建一个信号,映射以提取相对于某个视图的触摸位置,然后让我的目标类观察这个信号(或者只是有一个调用目标类上的方法的最终subscribeNext块)。

然而,似乎什么都做不到,也找不到一个好的榜样。

我想我应该写这样的东西(psuedo代码)

panRecognizer
    .rac_gestureSignal()
    .map { (pgr:UIPanGestureRecognizer) -> CGPoint in
        return pgr.locationInView(self.someUiView)
    }.subscribeNext { (location: CGPoint) -> Void in
        self.someNetworkDelegate.updatePosition(location)
    }

这样的事情可能吗(看起来很简单)?我是否试图以一种糟糕的方式使用该框架?

您实际上已经非常接近了。

但是不能有CGPoints中的RACSignals,因为CGPoint不是引用类型。一般来说,在ReactiveCocoa 2的世界中,您可以通过显式装箱和取消装箱NSValue之类的类型来绕过这一点,并进行一些转换:

panRecognizer.rac_gestureSignal()
    .map({ [unowned self] (pgr: AnyObject!) -> NSValue! in
        let pgr = pgr as! UIPanGestureRecognizer
        return NSValue(CGPoint: pgr.locationInView(self.someUiView))
    }).subscribeNext({[unowned self] locationValue in
        let location = locationValue.CGPointValue
        self.someNetworkDelegate.updatePosition(location)
    })

但是,通过将RACSignal转换为SignalProducer,您可以使用所需的漂亮类型。这样做…很麻烦,所以我使用以下助手:

extension SignalProducer {
    func castSignal<T>() -> SignalProducer<T, Error> {
        return self.map({ $0 as! T })
    }
    func cantError() -> SignalProducer<Value, NoError> {
        // If we inline this, Swift will try to implicitly return the fatalError
        // expression. If we put an explicit return to stop this, it complains
        // it can never execute. One is an error, the other a warning, so we're
        // taking the coward's way out and doing this to sidestep the problem.
        func swallowError(error: Error) -> SignalProducer<Value, NoError> {
            fatalError("Underlying signal errored! (error)")
        }
        return self.flatMapError(swallowError)
    }
}
extension RACSignal {
    func cast<T>() -> SignalProducer<T, NoError> {
        return self.toSignalProducer().cantError().map({ $0! }).castSignal()
    }
}

显然,如果要转换可能出错的信号,您需要不同的助手,但这对本例来说效果很好。

有了这些,你可以像这样写代码:

    self.reportTapRecognizer.rac_gestureSignal().cast()
        .map({ [unowned self] (pgr: UIPanGestureRecognizer) -> CGPoint in
            return pgr.locationInView(self.someUiView)
        }).startWithNext({ [unowned self] location in
            self.someNetworkDelegate.updatePosition(location)
        })

这基本上就是你上面写的方式。请注意,map调用中需要类型注释,以便cast可以正确推断其返回类型。

有了RAC4,这个应该能很好地工作。。

let gesRec = UIPanGestureRecognizer(target: self, action: "gesRecHandler:")
    view.addGestureRecognizer(gesRec)
    gesRec.rac_gestureSignal().toSignalProducer().map({ (x) -> CGPoint in
        guard let pan = x as? UIPanGestureRecognizer else {return CGPointZero}
        return pan.locationInView(self.view)
    }).startWithNext { (pointInView) -> () in
        print(pointInView)
    }

在RAC4中,存在一些与信号有关的变化。因此,您首先需要将RACSignal转换为信号生成器并开始观察它。这是关于将RACSignals转换为SignalProducer RACSignalToSignalProducer 的文章

相关内容

  • 没有找到相关文章

最新更新