使用 ReactiveCocoa 4 的简单 UIGestureRecogniser 示例
Simple UIGestureRecogniser example with ReactiveCocoa 4
努力让一个简单的 ReactiveCocoa 4 示例工作。
- 我的层次结构中有一个视图的平移手势识别器。
- 我为我的触摸事件指定了目的地 class(假设我想根据触摸位置生成网络数据包)。
所以看起来我想从我的手势识别器创建一个信号,映射以提取相对于某个视图的触摸位置,然后让我的目的地 class 观察这个信号(或者只是有一些最终的在我的目的地 class).
上调用方法的 subscribeNext 块
然而,似乎无法使任何工作正常进行,也找不到可效仿的好例子。
我想我应该写这样的东西(伪代码)
panRecognizer
.rac_gestureSignal()
.map { (pgr:UIPanGestureRecognizer) -> CGPoint in
return pgr.locationInView(self.someUiView)
}.subscribeNext { (location: CGPoint) -> Void in
self.someNetworkDelegate.updatePosition(location)
}
这样的事情可能吗(看起来很简单)?我可能试图以错误的方式使用该框架吗?
你真的很接近那里。
但是你不能有 RACSignal
和 CGPoint
,因为 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({ [=11=] 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({ [=11=]! }).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
可以正确推断其 return 类型。
对于 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
的文章
努力让一个简单的 ReactiveCocoa 4 示例工作。
- 我的层次结构中有一个视图的平移手势识别器。
- 我为我的触摸事件指定了目的地 class(假设我想根据触摸位置生成网络数据包)。
所以看起来我想从我的手势识别器创建一个信号,映射以提取相对于某个视图的触摸位置,然后让我的目的地 class 观察这个信号(或者只是有一些最终的在我的目的地 class).
上调用方法的 subscribeNext 块然而,似乎无法使任何工作正常进行,也找不到可效仿的好例子。
我想我应该写这样的东西(伪代码)
panRecognizer
.rac_gestureSignal()
.map { (pgr:UIPanGestureRecognizer) -> CGPoint in
return pgr.locationInView(self.someUiView)
}.subscribeNext { (location: CGPoint) -> Void in
self.someNetworkDelegate.updatePosition(location)
}
这样的事情可能吗(看起来很简单)?我可能试图以错误的方式使用该框架吗?
你真的很接近那里。
但是你不能有 RACSignal
和 CGPoint
,因为 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({ [=11=] 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({ [=11=]! }).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
可以正确推断其 return 类型。
对于 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
的文章