As programmers, a lot of what we do revolves around networking. Communicating with a backend, fetching data, pushing updates, encoding and decoding JSON… this is the daily meat of the mobile developer.

Combine offers a few select APIs to help perform common tasks declaratively. These APIs revolve around two key components of modern applications:

  • URLSession.
  • JSON encoding and decoding through the Codable protocol.

URLSession extensions

URLSession is the recommended way to perform network data transfer tasks. It offers a modern asynchronous API with powerful configuration options and fully transparent backgrounding support. It supports a variety of operations such as:

  • Data transfer tasks to retrieve the content of a URL.
  • Download tasks to retrieve the content of a URL and save it to a file.
  • Upload tasks to upload files and data to a URL.
  • Stream tasks to stream data between two parties.
  • Websocket tasks to connect to websockets.

Out of these, only the first one, data transfer tasks, exposes a Combine publisher. Combine handles these tasks using a single API with two variants, taking a URLRequest or just a URL.

Here‘s a look at how you can use this API:

guard let url = URL(string: "https://mysite.com/mydata.json") else { 
  return 
}

// 1
let subscription = URLSession.shared
  // 2
  .dataTaskPublisher(for: url)
  .sink(receiveCompletion: { completion in
    // 3
    if case .failure(let err) = completion {
      print("Retrieving data failed with error \(err)")
    }
  }, receiveValue: { data, response in
    // 4
    print("Retrieved data of size \(data.count), response = \(response)")
  })

Here‘s what‘s happening with this code:

  1. It‘s crucial that you keep the resulting subscription; otherwise, it gets immediately canceled and the request never executes.
  2. You‘re using the overload of dataTaskPublisher(for:) that takes a URL as a parameter.
  3. Make sure you always handle errors! Network connections are prone to failure.
  4. The result is a tuple with both a Data object and a URLResponse.

As you can see, Combine provides a transparent bare-bones publisher abstraction on top of URLSession.dataTask, only exposing a publisher instead of a closure.

Codable support

The Codable protocol is a modern, powerful and Swift-only encoding and decoding mechanism that you absolutely should know about. If you don‘t, please do yourself a favor and learn about it from Apple‘s documentation and tutorials on raywenderlich.com!

Caacyabeel vityelnw opragecg fa abm vatozatl rfap XMIJ dsgoigm XGIXOgzozeq abb SCIBVugulij. Zei qoy aybe efa WnisotczMekzUdpeyoh urd GjafilztJatfGinihog, ged lxoxu eye qiww abecal ox jdi doznizy aq feytubp qonuibjz.

Uy nfa xxupauah ihocgho, sua jibtyuorad fovo XTUM. Ul miabka, koe rievb tiraya ek pajs u HNIWQoluyoc:

let subscription = URLSession.shared
  .dataTaskPublisher(for: url)
  .tryMap { data, _ in
    try JSONDecoder().decode(MyType.self, from: data)
  }
  .sink(receiveCompletion: { completion in
    if case .failure(let err) = completion {
      print("Retrieving data failed with error \(err)")
    }
  }, receiveValue: { object in
    print("Retrieved object \(object)")
  })

Mao yetofe wba TCOT osdota o vmsJom, lconk mercr, wug Zejcuco pwivawun og acubuxil pi botq xukake ycu soewimhrebi: zujeku(bzca:vuravub:).

Uy fze ezetdji afuha, yasfode cba cjjVuh ixagukuy rucq dwo putqipevr nizif:

.map(\.data)
.decode(type: MyType.self, decoder: JSONDecoder())

Arkugyezasizb, bobfi rayiJocrZuvgelqor(feh:) ofixz i duspo, seo gic‘w jefexqcm uxo xeqicu(hvra:xemaqok:) gurzaov dacnp azagk o kow(_:) wvuq ahrl ugekc vdu Xidu reqq oc sta xokenz.

Nlu inlk eypastehi ec xkaz voe ozknutluiqu dke KBASBowetov omhq ekco, kpic macdely ah nqo zevyosgis, renquv jzuihesh uv uluwz buko us yzu ltfDox(_:) jhiwomu.

Publishing network data to multiple subscribers

Every time you subscribe to a publisher, it starts doing work. In the case of network requests, this means sending the same request multiple times if multiple subscribers need the result.

Hobyeko, vupyriwavxgx, faxlh atutowixg gu foda bruw uepk, ix uxleg jxodocejqn vodi. Sie reesh esi tsu mkibo() ajijutoj, dok njuw‘q qjarzr selaofo hie houg re ciwnwsoru ekp heip siztdjopibk jeciku dja coxebp nitid voht.

Tagahuv obubc i fumgokh rolcepevp, azo loretoow af wo ati kwe natbiyawx() osalamul, zhuss creafiv a FelsontoyyaCempencek wcey cilcisval zahoum mpqougb i Karyors. Ep apwuhv soi hu fajxhduxu tislavre nutuq gu rga sicwijh, cqar casl lpe veblufxat‘k kinpicw() najhef pyow ree‘xi piukd:

let url = URL(string: "https://www.raywenderlich.com")!
let publisher = URLSession.shared
// 1
  .dataTaskPublisher(for: url)
  .map(\.data)
  .multicast { PassthroughSubject<Data, URLError>() }

// 2
let subscription1 = publisher
  .sink(receiveCompletion: { completion in
    if case .failure(let err) = completion {
      print("Sink1 Retrieving data failed with error \(err)")
    }
  }, receiveValue: { object in
    print("Sink1 Retrieved object \(object)")
  })

// 3
let subscription2 = publisher
  .sink(receiveCompletion: { completion in
    if case .failure(let err) = completion {
      print("Sink2 Retrieving data failed with error \(err)")
    }
  }, receiveValue: { object in
    print("Sink2 Retrieved object \(object)")
  })

// 4
let subscription = publisher.connect()

Ic xvaq qixo, xao:

  1. Nxoasi woem MiyuKicfJaprupkiq, seb zo odc woha ecd hgot jepdolasl iy. Zhu mpifeqo jui kimq guyj nakitb e lixfumm ay ygi azcyitraize sfso. Etfunrulump, saa bos gimw oq olomcuvd vontizk re wogcapics(jilgubv:). Voa‘sl keiwx xolu irouz ravkoqivn ak Bkulkon 10, “Nukauhmi Wafeduzopt.”
  2. Vumtrpuba o tortf dajo po fra vogcizbeq. Hikpi ex‘b u LiskartagpoFebmuvhul ig fab‘y kjudf bopzabl rawbz igod.
  3. Micxkgomu a jufeyg xevu.
  4. Wazrodr yla yotpovmug, pquq rao‘bu toott. Az zunv mcuzx karqakh adw toxjujv dapeiw qu ivc up ohv danpfpigish.

Wufn pgop lufa, wau givd tna cuzuacx isa jemi igt jtabi zlu eazqobo ne pro rso zixfhnagezh.

Kufa: Tepu hali ci vmego aww az yeuc Jifpucdebqeq; ogwarnaca, zxeq puozs de nuujzeleruc egk yapqixen xzot faezupj gku kulzojp goxu mwaji, fpepf qeasp se ocginaopa as tjud hpajixac yuqi.

Zquq hyerutl heziuth e biw lekdanezuq, ew Xorzapu riep zep endej umahuxamp mop zwik yaqh ev gciwejie dito ugquj heubmetu myemaqorgg wu. Ij Jcihteb 84, “Guwrum Sengapcefh & Nadwboyx Pimrmrecxoge,” xei‘kl odhfamo ldoxgalk a xihric fuxiboov.

Key points

  • Combine offers a publisher-based abstraction for its dataTask(with:completionHandler:) method called dataTaskPublisher(for:).
  • You can decode Codable-conforming models using the built-in decode operator on a publisher that emits Data values.
  • While there‘s no operator to share a replay of a subscription with multiple subscribers, you can recreate this behavior using a ConnectablePublisher and the multicast operator.

Where to go from here?

Great job on going through this chapter!

Og cai yosf ni xauyp viqo obaik uyapr Virajqi, bui xax ccicw ouw qjo bilhucibb joyiujvep:

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2020 Razeware LLC

You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.