#swift #generics #rx-swift
#swift #обобщения #rx-swift
Вопрос:
Вот функция:
func registerFor<Element>(relayId id: String) -> Driver<Element>? {
guard let relay = relays[id] as? BehaviorRelay<Element> else { return nil }
return relay.asObservable()
.distinctUntilChanged { a, b in
return a != b
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: Element())
}
distinctUntilChanged
Строка выдает следующую ошибку:
Contextual closure type '(Element) throws -> _' expects 1 argument,
but 2 were used in closure body
asDriver
Строка выдает следующую ошибку (конечно):
Non-nominal type 'Element' does not support explicit initialization
Контекст: У меня есть класс, который в идеале имеет коллекцию BehaviorRelay
ов различных типов (строки, целые числа и т.д.). Element
обычно используется для этих типов, но это создает две проблемы:
distinctUntilChanged
настаивает на наличии замыкания (например: если бы этот метод вернулся,Driver<String>
было бы достаточно просто использовать,distinctUntilChanged()
но обобщениеElement
заставляет его жаловаться на отсутствие замыкания);onErrorJustReturn
требуется конкретное значение, ноElement
оно является общим.
Следующий «обходной путь» может сработать, но я подозреваю, что есть лучшие решения
protocol Inii {
init()
}
func registerFor(relayId id: String, def: Inii.Type) -> Driver<Inii>? {
return relays[id]?.asObservable()
.distinctUntilChanged { _, _ in
return true
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: def.init())
}
Хотя я все еще не уверен, что поместить в distinctUntilChanged
закрытие.
Приложение A
Я считаю, что при реализации distinctUntilChanged
замыкания для не общего типа требуется следующее:
.distinctUntilChanged { previousValue, currentValue in
return previousValue == currentValue
}
Однако при использовании с обобщением Element
по-прежнему выдается следующая ошибка:
Contextual closure type '(Inii) throws -> _' expects 1 argument,
but 2 were used in closure body
Приложение B
Вот еще одна альтернатива с немного другой проблемой:
protocol Inii {
init()
}
var relay = BehaviorRelay<String>(value: "")
func registerFor<Element>(def: Element.Type) -> Driver<Element> where Element: Inii {
return relay.asObservable()
.distinctUntilChanged { previousValue, currentValue in
return previousValue == currentValue
}.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: def.init())
}
Ошибка в этом случае заключается в:
Member 'next' in 'Event<_>' produces result of type 'Event<Element>',
but context expects 'Event<_>'
в observer.on
строке
Ответ №1:
Вы можете использовать distinctUntilChanged()
без закрытия, если Element
соответствует Equatable
:
protocol EmptyInit {
init()
}
func registerFor<Element>(relayId id: String) -> Driver<Element>? where Element: Equatable, Element: EmptyInit {
guard let relay = relays[id] as? BehaviorRelay<Element> else { return nil }
return relay.asObservable()
.distinctUntilChanged()
.flatMapLatest { value in
return Observable.create { observer in
observer.on(.next(value))
return Disposables.create()
}
}.asDriver(onErrorJustReturn: Element())
}