Использование обобщений Swift в функции получения RxSwift - различные проблемы - PullRequest
1 голос
/ 14 марта 2019

Вот функция:

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 различных типов (Strings, Ints и т. Д.).Element в общем относится к этим типам, но это создает две проблемы:

  1. distinctUntilChanged настаивает на наличии замыкания (например: если этот метод вернул Driver<String>, он будет просто использоватьdistinctUntilChanged() но универсальный Element заставляет его жаловаться на отсутствие закрытия);
  2. 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
}

Однако при использовании сgeneric 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 Ответ

1 голос
/ 14 марта 2019

Вы можете использовать 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())
}
...