Search code examples
swiftcombine

Combine: Publisher sends text change even once


I want to observe changes on UISearchController's text, here is my setup (and I'm pretty new to Combine):

private var searchQuery: String? {
    didSet {
        print(searchQuery)
    }
}

private var disposable: AnyCancellable?


func bindSearchQuery() {
    disposable = searchController.searchBar.publisher(for: \.text)
        .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
        .sink { value in
            if let _value = value {
                self.searchQuery = _value
            }
        }
}

And I see this once only in the console, on load:

Optional("")


Solution

  • I had to create an AnyPublisher object then received its changes on an AnyCancellable object:

    final class SearchResult {
        var resultText: String? {
            didSet {
                print(resultText)
            }
        }
    }
    
    ///
    @Published var searchQuery: String = ""
    
    private var validateQuery: AnyPublisher<String?, Never> {
        return $searchQuery
            .debounce(for: 0.3, scheduler: RunLoop.main)
            .removeDuplicates()
            .flatMap { query in
                return Future { promise in
                    self.search(query: query) { result in
                        switch result {
                        case .success(let _output):
                            print(_output)
                            promise(.success(_output))
                        case .failure:
                            print("Failed search")
                            promise(.success(nil))
                        }
                    }
                }
            }
            .eraseToAnyPublisher()
    }
    
    private var cancelable: AnyCancellable?
    private var result = SearchResult()
    
    ///
    
    func bindSearchQuery() {
        cancelable = validateQuery
            .receive(on: RunLoop.main)
            .assign(to: \.resultText, on: result)
    }
    

    And everytime user types in the search box I update searchQuery:

    func updateSearchResults(for searchController: UISearchController) {
         self.searchQuery = searchController.searchBar.text ?? ""
    }