【问题标题】:Simple UIGestureRecogniser example with ReactiveCocoa 4带有 ReactiveCocoa 4 的简单 UIGestureRecogniser 示例
【发布时间】:2016-01-08 19:37:19
【问题描述】:

努力让一个简单的 ReactiveCocoa 4 示例正常工作。

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

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

但是,似乎无法让任何东西发挥作用,也找不到一个好的榜样。

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

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

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

【问题讨论】:

  • 此答案建议为此利用 RAC 2 扩展:stackoverflow.com/a/34169581/2128900。不过,我不知道是否有办法仅使用 RAC 4 来做到这一点(也许存在第 3 方扩展)?
  • @MichałCiuba 是的,我看到了,不能在 RAC 4 中编译。

标签: ios swift swift2 reactive-cocoa reactive-cocoa-4


【解决方案1】:

其实你离那里很近。

但是你不能拥有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 可以正确推断其返回类型。

【讨论】:

    【解决方案2】:

    使用 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 转换为信号生成器并开始观察它。您可以在FrameworkOverview 中阅读有关信号生产者的信息 .这是关于将 RACSignals 转换为 SignalProducer 的文章RACSignalToSignalProducer

    【讨论】:

    • 当然你应该在闭包中添加 [weak self]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 2017-10-17
    • 2012-02-13
    • 2014-01-05
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多