1

Here's the function:

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())
}

The distinctUntilChanged line throws the following error:

Contextual closure type '(Element) throws -> _' expects 1 argument, 
but 2 were used in closure body

The asDriver line throws the following error (of course):

Non-nominal type 'Element' does not support explicit initialization

Context: I have a class that ideally has a collection of BehaviorRelays of various types (Strings, Ints, etc). Element stands in generically for these types, but that creates two problems:

  1. distinctUntilChanged insists of having a closure (eg: if this method returned Driver<String> it would be content simply to use distinctUntilChanged() but the generic Element makes it complain about missing a closure);
  2. onErrorJustReturn requires a concrete value, but Element is generic.

The following "workaround" might work but I suspect there are better solutions

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())
}

Although I'm still unsure what to put in the distinctUntilChanged closure.


Appendix A

I believe that the following is what is required if one is implementing the distinctUntilChanged closure for a non-generic type:

.distinctUntilChanged { previousValue, currentValue in
    return previousValue == currentValue
}

However, when used with the generic Element the following error is still thrown:

Contextual closure type '(Inii) throws -> _' expects 1 argument, 
but 2 were used in closure body

Appendix B

Here's another alternative with a slightly different problem:

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())
}

Error in this case being:

Member 'next' in 'Event<_>' produces result of type 'Event<Element>', 
but context expects 'Event<_>'

at the observer.on line

1 Answer 1

1

You can use distinctUntilChanged() without a closure as long as Element conforms to 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())
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.