Conditionally add operations to pipeline in Combine (Swift)

Viewed 138

Is there a way to conditionally execute the parts of the pipeline ? Say in the code below i would want a bool which determines whether the api call and the debounce are executed or not (if true execute the debounce and api call, if false erase without them) ?

    var flag: Bool // true: validate university via server, 
                   // false: only validate with operations before debounce and flat map

    init(flag: Bool) {
        self.flag = flag
        
        validate
            .receive(on: RunLoop.main)
            .sink { [weak self] value in
                self?.loading = false
                self?.validated = value
            }
            //.assign(to: \.validated, on: self)
            .store(in: &cancellables)
    }

    private var validate: AnyPublisher<String?, Never> {
        $value
            .dropFirst()
            .removeDuplicates()
            .trim()
            .filter { value in
                value.contains("@") && value.contains(".")
            }
            .debounce(for: 1, scheduler: RunLoop.main) // from here on conditionally
            .flatMap { value in
                return Future { promise in
                    self.loading = true
                    Task {
                        Firebase.validate(email: value) { error in
                            promise(.success(error != nil ? nil : value))
                        }
                    }
                }
            }
            .eraseToAnyPublisher()
    }
1 Answers

This one is simpler than what I thought you wanted... All you need is a simple filter:

let sink = source
    .combineLatest(boundary)
    .filter { $0.1 }
    .map { $0.0 }

In other words:

$value
    .dropFirst()
    .removeDuplicates()
    .trim()
    .filter { $0.contains("@") && $0.contains(".") }
    .combineLatest(boundary)
    .filter { $0.1 }
    .map { $0.0 }
    .debounce(for: 1, scheduler: RunLoop.main)
    .flatMap { value in
        Future { [weak self] promise in
            self?.loading = true
            Task {
                Firebase.validate(email: value) { error in
                    self?.loading = false
                    promise(.success(error != nil ? nil : value))
                }
            }
        }
    }
    .eraseToAnyPublisher()
Related