Расширение SignalProducerType, если значением является массив<SomeProtocol>

У меня есть протокол для выборки объектов базы данных по PrimaryKey

typealias PrimaryKey = String

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

и я хочу расширить SignalProducerType, чтобы иметь возможность работать с SignalProducer.Value этого типа.

Таким образом, расширение Single для одного объекта (например, не в массиве) работает нормально и реализовано следующим образом:

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) Генерирует ошибку:

"[PrimaryKeyConvertible]" не конвертируется в "[GoogleContact]"

1 ответ

Хм, хотя я не совсем уверен, в чем проблема, но я думаю, что следующая реализация может быть тем, что вы хотите.

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) }
        }
    }
}
Другие вопросы по тегам