Расширение 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) }
}
}
}