扩展SignalProducerType以防值为数组<someprotocol>

时间:2016-03-11 01:21:00

标签: swift protocols reactive-cocoa reactive-cocoa-4

我有一个通过PrimaryKey获取数据库对象的协议

typealias PrimaryKey = String

protocol PrimaryKeyConvertible {
    var pkValue : PrimaryKey { get }
    static func pkObject(key: PrimaryKey) -> Self?
}

我希望扩展SignalProducerType以便能够对该类型的SignalProducer.Value进行操作。

因此单个对象扩展(单个非数组)工作正常,并按如下方式实现:

extension SignalProducerType
   where Value: PrimaryKeyConvertible
{
    func fetchOnMainThread() -> SignalProducer<Value?, Error> {
        return
        self.map{ (obj: Value) -> PrimaryKey in
            return obj.pkValue
        }
        .observeOn(UIScheduler())
        .map{ (key: PrimaryKey) -> Value? in
            return Value.pkObject(key)
        }
    }
}

但是当我尝试在这些元素的数组上实现它时,我遇到了一些编译挑战:

extension SignalProducerType
{
    func fetchOnMainThread<P: PrimaryKeyConvertible where Self.Value == Array<P>>() -> SignalProducer<[P], Error> { //(1)
        return self.map({ (value: Self.Value) -> [PrimaryKey] in
            return value.map{ $0.pkValue } //(2)
        })
    }
}

(1)我怀疑签名没有正确地将想法传达给编译器

(2)产生以下错误:

  

如果没有更多的上下文,表达的类型是不明确的

我试图解决的问题是如何让编译器认识到SignalProducer正在Array<P>上运行,其中P是PrimaryKeyConvertible并且.map对其进行操作。

我目前解决阵列问题的方法是使用下面列出的通用函数实现:

func fetchOnMainThread<Value: PrimaryKeyConvertible, Error: ErrorType>
    (signal: SignalProducer<[Value], Error>) -> SignalProducer<[Value], Error> { 
        return signal
            .map{ (convertibles: [Value]) -> [PrimaryKey] in
                return convertibles.map { $0.pkValue }
            }
            .observeOn(UIScheduler())
            .map{ (keys: [PrimaryKey]) -> [Value] in
                return keys.flatMap{ Value.pkObject($0) }
        }
}

然后用于例如:

extension GoogleContact: PrimaryKeyConvertible {...}

extension GoogleContact {
  static func fetchGoogleContactsSignal() -> SignalProducer<[GoogleContact], GoogleContactError> { ...}
}

,呼叫网站就像:

let signal = fetchOnMainThread(GoogleContacts.fetchGoogleContactsSignal()).onNext...

我希望将它作为一个像往常一样流动的扩展

GoogleContacts
  .fetchGoogleContactsSignal()
  .fetchOnMainThread()

更新

我试过的另一个版本的功能:(@ J.Wang)

extension SignalProducerType
    where Value == [PrimaryKeyConvertible]
{
    func fetchArrayOnMainThread2<T: PrimaryKeyConvertible>() -> SignalProducer<[T], Error> {
        return self
            .map{ (values: Self.Value) -> [PrimaryKey] in
                return values.map{ $0.pkValue }
            }
            .deliverOnMainThread()
            .map{ (keys: [PrimaryKey]) -> [T] in
                return keys.flatMap{ T.pkObject($0) }
            }
    }

}


    let signal =
        GoogleContacts
            .fetchGoogleContactsSignal()
            .fetchArrayOnMainThread2() //(3) 

(3)生成错误:

  

&#39; [PrimaryKeyConvertible]&#39;不能兑换为[GoogleContact]&#39;

1 个答案:

答案 0 :(得分:0)

嗯,虽然我不太确定问题是什么,但我认为以下实施可能就是你想要的。

extension SignalProducerType where Value == [PrimaryKeyConvertible]
{
    func fetchOnMainThread() -> SignalProducer<[PrimaryKey], Error> {
        return self.map { value in
            value.map { $0.pkValue }
        }
    }
}

试试这个:

extension SignalProducerType where Value == [PrimaryKeyConvertible]
{
    func fetchOnMainThread<T: PrimaryKeyConvertible>() -> SignalProducer<[T], Error> {
        return self.map { value in
            value.map { $0.pkValue }
        }.map { keys in
            keys.flatMap { T.pkObject($0) }
        }
    }
}