ReactiveCocoa subscribeNext用于Swift中的可选项



我在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)
        }
    }
}

最新更新