У меня есть протокол для извлечения объектов базы данных по PrimaryKeyРасширение SignalProducerType в случае, если значение является массивом <SomeProtocol>
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) производит следующее сообщение об ошибке:
Type of expression is ambiguous without more context
вопрос я пытаюсь решить, как позволить компилятору распознавать SignalProducer работает на Array<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()
Update
другой версии от функции, которую я пробовал: (@ 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]' is not convertible to '[GoogleContact]'
где положение в расширении подписи является хорошей идеей, но в конце концов становится проблемой на втором отображение из [PrimaryKey] назад к [ PrimaryKeyConvertible] –
@EdwardAshak Извините, не знал, что вы хотите его вернуть. Проверьте мое обновление. –
@wang, я сделал, вы должны посмотреть мое обновление выше –