在合并(Swift)中有条件地向管道添加操作

gpfsuwkq  于 2023-02-28  发布在  Swift
关注(0)|答案(2)|浏览(103)

有没有一种方法可以有条件地执行流水线的各个部分?在下面的代码中,我想要一个bool来决定是否执行API调用和去抖动(如果为真,则执行去抖动和api调用,如果为假,则不执行它们而删除)?

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

iovurdzv1#

这一个比我想象的要简单...你所需要的只是一个简单的过滤器:

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

换句话说:

$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()
kpbwa7wx

kpbwa7wx2#

为了不使事情过于复杂,我将展示一个如何实现条件去抖动的最小示例。

更新:

如果你想要一个100%被动的方法,你可以这样做:

var subscription: AnyCancellable

subscription = $value
    .map { val in
        if <condition> {
            Just(val)
                .debounce(for: 1, scheduler: RunLoop.main)
                .eraseToAnyPublisher()
        } else {
            Just(val)
                .eraseToAnyPublisher()
        }
    }
    .switchToLatest() // You might not need this but most probably you do
    .sink {
      // Do whatever you need
    }

在这里,我们根据条件将一个发布者转换为另一个发布者,然后使用.switchToLatest()跳转到最新的发布者,丢弃之前的发布者。

原始答案:

这种方法不是完全被动的(还没有使用.debounce方法),但它可以完成任务:

var timer: Timer?
var subscription: AnyCancellable

subscription = $value
    .sink {
        // Invalidating timer before condition check to not let it
        // trigger the debounced function after the `value` has changed
        timer?.invalidate()

        if <condition> {
            timer = Timer.scheduledTimer(
                 withTimeInterval: 0.5,
                 repeats: false
            ) { _ in
                // Do the stuff you need with debounce
            }
        } else {
            // Do the stuff you need without debounce
        }
    }

相关问题