5

I recently encounter two data fetching (download) API that performs seemingly the same thing to me. I cannot see when should I use one over the other.

I can use URLSession.shared.dataTask

    var tasks: [URLSessionDataTask] = []

    func loadItems(tuple : (name : String, imageURL : URL)) {
        let task = URLSession.shared.dataTask(with: tuple.imageURL, completionHandler :
        { data, response, error in
            guard let data = data, error == nil else { return }
            DispatchQueue.main.async() { [weak self] in
                self?.displayFlag(data: data, title: tuple.name)
            }
        })
        tasks.append(task)
        task.resume()
    }

    deinit {
        tasks.forEach {
            $0.cancel()
        }
    }

Or I can use URLSession.shared.dataTaskPublisher

    var cancellables: [AnyCancellable] = []

    func loadItems(tuple : (name : String, imageURL : URL)) {
        URLSession.shared.dataTaskPublisher(for: tuple.imageURL)
            .sink(
                receiveCompletion: {
                    completion in
                    switch completion {
                    case .finished:
                        break
                    case .failure( _):
                        return
                    }},
                receiveValue: { data, _ in DispatchQueue.main.async { [weak self] in self?.displayFlag(data: data, title: tuple.name) } })
            .store(in: &cancellables)
    }

    deinit {
        cancellables.forEach {
            $0.cancel()
        }
    }

I don't see their distinct differences, as both also can fetch, and both also provide us the ability to cancel the tasks easily. Can someone shed some light on their differences in terms of when to use which?

Elye
  • 53,639
  • 54
  • 212
  • 474
  • The second one uses the new [Combine](https://developer.apple.com/documentation/combine) framework – Joakim Danielson Oct 23 '20 at 05:36
  • 2
    He knows that. He's asking why use Combine pattern. – Rob Oct 23 '20 at 05:37
  • Thanks, @JoakimDanielson. When should we use the original one, and when should we use the Combine framework? What's the benefit of using the Combine framework? Sorry, I'm from the Android Dev background, hence limited exposure to iOS. – Elye Oct 23 '20 at 05:39
  • I don’t see what you see but it doesn’t matter, the question is too broad anyway – Joakim Danielson Oct 23 '20 at 05:39
  • 1
    When Claus was suggesting Combine, I think he was suggesting that you wouldn't need the `deinit` cleanup. When the publisher is released, the request should cancel automatically (which is why he recommended it in answer to your other question). Personally, I'd introduce Combine if that solved other problems (e.g. controlling degree of concurrency, chaining other publishers or combine operators, already using it for other things in the project). I'm not sure I'd introduce it here just for the purposes of not having to manually cancel the request, but it's up to you. It's a matter of opinion. – Rob Oct 23 '20 at 05:41
  • 1
    You need to read up on Combine and decide yourself but Combine is the new framework for asynchronous handling so it’s probably worth considering it. – Joakim Danielson Oct 23 '20 at 05:43
  • Thanks, @JoakimDanielson @Rob. Does the above performing `cancel` in `deinit` for the `cancellable` is redundant? – Elye Oct 23 '20 at 05:48
  • Good to know when to use is a preference, and the Combine advantage can only be seen when we chain it with other operations. Sounds to me similar to Android, the native way to fetching provided by Android is so tricky, hence we use the RxJava framework mostly, and never recommend anyone use the Android version (i.e. AsyncLoad) directly. Can this be the case for the above as well? – Elye Oct 23 '20 at 05:48

1 Answers1

10

The first one is the classic. It has been present for quite some time now and most if not all developers are familiar with it.

The second is a wrapper around the first one and allows combining it with other publishers (e.g. Perform some request only when first two requests were performed). Combination of data tasks using the first approach would be far more difficult.

So in a gist: use first one for one-shot requests. Use second one when more logic is needed to combine/pass results with/to other publishers (not only from URLSession). This is, basically, the idea behind Combine framework - you can combine different ways of async mechanisms (datatasks utilising callbacks being one of them).

More info can be found in last year's WWDC video on introducing combine.

Eimantas
  • 48,927
  • 17
  • 132
  • 168
  • Thanks @Eimantas. I'll check out https://heckj.github.io/swiftui-notes/ further. For the above code, should I still be doing `cancel` for the `cancelable` in the `deinit`? Is that redundant? – Elye Oct 23 '20 at 05:50
  • I am not very well familiar with behavior of cancellables. You can print something in receiveValue block and see if it prints anything after you deallocate an instance hding cancellables. – Eimantas Oct 23 '20 at 06:01
  • I check here it states that it should be cancellable by itself. https://stackoverflow.com/a/59023309/3286489 – Elye Oct 23 '20 at 08:40