Пользовательский flatMapLatest с нулевой оберткой

У меня есть тестовая функция, которая наблюдает за значениями и сопоставляет их с другим Observable:

private func test1() {
    selectedTagsVariable
        .asObservable()
        .flatMapLatest { [weak self] tags -> Observable<PostSet> in
            guard let strongSelf = self else { return .empty() }
            return strongSelf.postSetObservable(for: tags)
        }
}

Это нормально, но я не хочу каждый раз проверять значение self на ноль. Я, конечно, могу заменить weak на unowned, но это не правильно.

Итак, я создал пользовательский flatMapLatest:

extension ObservableType {

func xflatMapLatest<A:AnyObject, O: ObservableType>(weak obj: A, selector: @escaping (A, Self.E) throws -> O) -> Observable<O.E> {
    return flatMapLatest { [weak obj] value -> Observable<O.E> in
        guard let strongObj = obj else {
            return Observable.empty()
        }
        return try selector(strongObj, value) as! Observable<O.E>
    }
}
}

и это выглядит так:

private func test2() {
    selectedTagsVariable
        .asObservable()
        .xflatMapLatest(weak: self) { obj, tags -> Observable<PostSet> in
            return obj.postSetObservable(for: tags)
        }
}

Вопрос: мне не нравится преобразование типа в функции xflatMapLatest в возвращаемом типе (as! Observable<O.E>). Можно как-то удалить? Помогите рефакторить этот метод :)


person Nikita Ermolenko    schedule 26.01.2017    source источник


Ответы (1)


Что вы хотите, так это отразить оператор flatMapLatest с простой модификацией. Взгляните на его подпись:

func flatMapLatest<O : ObservableConvertibleType>(_ selector: @escaping (Self.E) throws -> O) -> RxSwift.Observable<O.E>

Как видите, результирующий тип замыкания selector должен соответствовать ObservableConvertibleType, определение которого находится здесь:

public protocol ObservableConvertibleType {
    associatedtype E
    public func asObservable() -> RxSwift.Observable<Self.E>
}

Зная это, довольно легко увидеть, какие небольшие изменения вам нужно сделать, чтобы заставить его работать:

extension ObservableType {
    func flatMapLatestWeak<A: AnyObject, O: ObservableConvertibleType>(weak obj: A, selector: @escaping (A, E) throws -> O) -> Observable<O.E> {
        return flatMapLatest { [weak obj] value -> Observable<O.E> in
            guard let strongObj = obj else {
                return Observable.empty()
            }
            return try selector(strongObj, value).asObservable()
        }
    }
}

Кроме того, вы можете сократить этот метод, используя map Optional<T>:

extension ObservableType {
    func flatMapLatestWeak<A: AnyObject, O: ObservableConvertibleType>(weak obj: A, selector: @escaping (A, E) throws -> O) -> Observable<O.E> {
        return flatMapLatest { [weak obj] value in
            try obj.map{ try selector($0 , value).asObservable() } ?? .empty()
        }
    }
}
person Silvan Mosberger    schedule 26.01.2017