Search code examples
iosswiftcombine

Combine: resetting observed boolean within sink() call?


I have the following code:

    $myBoolean
        .debounce(for: 2, scheduler: RunLoop.main)
        .removeDuplicates()
        .sink { newValue in
            self.myBoolean = false
            ....... 
            ...... (closure called every 2 seconds if I don't use `removeDuplicates()`)
        }
        .store(in: &subscribers)

I am using sink() on a @Published var in my observable object. Different parts of the app can set that boolean to true. When that happens, I want the code in sink() to run.

When that happens I want the code to reset myBoolean to false. So, only when I know the sink() code runs I want the boolean to be set back to false.

How can I set myBoolean back to false only when the sink() code runs without cause endless calls to the sink()?

myBoolean is declared like so:

@Published fileprivate var myBoolean:Bool = false

Solution

  • Using Custom type MyBool and filter operator you can get similar behaviour.

    
    import Combine
    
    class Abc: ObservableObject {
        struct MyBool: Equatable {
            let value: Bool
            let isFromSinkCall: Bool
        }
        
        @Published var myBoolean: MyBool = .init(value: true, isFromSinkCall: false)
        
        private var subscribers = Set<AnyCancellable>()
        
        init() {
            setup()
        }
        
        func setup() {
            $myBoolean
                .debounce(for: 2, scheduler: RunLoop.main)
                .removeDuplicates()
                .filter({ !$0.isFromSinkCall })
                .sink { newValue in
                    self.myBoolean = .init(value: false, isFromSinkCall: true)
                }
                .store(in: &subscribers)
        }
    }