Home > Back-end >  Swift, Combine, cancel on the flight and replace with the new request operator
Swift, Combine, cancel on the flight and replace with the new request operator

Time:12-13

I've got this network call for fetching images.

func load() {
        guard let url = URL(string: urlString)
        else { return }

        subscription = URLSession.shared.dataTaskPublisher(for: url)
            .map({ UIImage(data: $0.data) })
            .replaceError(with: nil)
            .receive(on: RunLoop.main)
            .sink(receiveValue: { [weak self] in self?.image = $0 })
    }

This is triggered by the text field being filled. After each letter is typed, I would like my publisher to wait with the execution for let's say 2 seconds, unless a user typed another letter. If that happens, I'd like the timer to reset to 2 seconds again.

Is there any on the fly cancel operator if the new request has been sent in the meanwhile?

Thanks for all the help.

CodePudding user response:

This is a pretty standard thing to do with a reactive library and easily accomplished. The switchToLatest operator is the one that does the magic.

@available(iOS 14.0, *)
final class ViewController: UIViewController {
    var textField: UITextField!
    var image: UIImage?
    var cancelBag = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()

        textField.textPublisher // this is from the `CombineCocoa` library
            .debounce(for: 2, scheduler: RunLoop.main)
            .compactMap { makeURL(from: $0) }
            .map {
                URLSession.shared.dataTaskPublisher(for: $0)
                    .catch { _ in Empty() } // what do you want to do with loading errors?
            }
            .switchToLatest()
            .map { UIImage(data: $0.data) }
            .receive(on: RunLoop.main)
            .sink(receiveValue: { [weak self] in self?.image = $0 })
            .store(in: &cancelBag)
    }
}

func makeURL(from: String?) -> URL? {
    // build and return the correct URL for the image request
    fatalError()
}
  • Related