我在RACSignal
上写了一个扩展,用于许多常见的ReactiveCocoa操作,map
, filter
, subscribeNext
,以便我可以显式地指定回调块中的类型。map
变成mapAs
, filter
变成filterAs
, subscribeNext
变成subscribeNextAs
(等等,等等)
func subscribeNextAs<T>(nextClosure:(T) -> ()) -> RACDisposable! {
return self.subscribeNext {
(next) -> () in
if let nextAsT = next as? T {
nextClosure(nextAsT)
}
}
}
然而,我注意到的一个问题是可选值没有传递给nextClosure
,因为if let nextAsT
失败了。
我如何重写这个扩展函数,使subscribeNextAs
允许我转换可选和非可选?
的例子:
RACObserve(someObject, potentiallyOptionalTitle).subscribeNextAs({
(next: String?) in
})
RACObserve(someObject, nonOptionalTitle).subscribeNextAs({
(next: String) in
})
您需要为nextClosure
参数指定泛型类型的可选性。在您的情况下,您可以将通用subscribeNext
定义为:
func subscribeNextAs<T>(nextClosure:(T!) -> ()) -> RACDisposable {
return self.subscribeNext {
(next) -> () in
nextClosure(next != nil ? next as! T : nil)
}
}
这里的缺点是可选性是隐藏的,这意味着你不能保证在编译时是否适当地处理nil值。你必须小心不要在你不期望的地方传递nil值。
另一个选择是使用升级到RAC 4。x和使用通用的Signal<T>
,但它仍然在Alpha中,所以如果你发布到prod,不要这样做。
subscribeNext
采用(AnyObject!)->Void
类型的闭包。这个AnyObject!
不能强制转换为String?
。在playground中试试下面的代码:
let str: String? = "1"
str is String? // true
let anyObjStr: AnyObject? = "1"
anyObjStr is String? // false, not the same type
anyObjStr is String // true, the unwrapped value can be cast to String
anyObjStr is NSString // true
要解决这个问题,你可以添加方法的一个重载,带有可选参数:
func subscribeNextAs<T>(nextClosure:(T?) -> ()) -> RACDisposable! {
return self.subscribeNext {
(next) -> () in
if let unwrapped = next {
if let nextAsT = unwrapped as? T {
nextClosure(nextAsT)
}
} else {
nextClosure(nil)
}
}
}