In the past few chapters, you learned about quite a few practical applications of the Combine integration in Foundation types. You learned how to use URLSession‘s data task publisher to make network calls, you saw how to observe KVO-compatible objects with Combine and more.
In this chapter, you will combine your solid knowledge about operators with some of the Foundation integrations you just discovered and will work through a series of tasks like in the previous “In Practice” chapter. This time around, you will work on building a Hacker News API client.
“Hacker News,” whose API you are going to be using in this chapter, is a social news website focused on computers and entrepreneurship. If you haven‘t already, you can check them out at: https://news.ycombinator.com.
In this chapter, you will work in an Xcode playground focusing only on the API client itself.
In Chapter 15, “In Practice: Combine & SwiftUI,” you will take the completed API and use it to build a real Hacker News reader app by plugging the network layer into a SwiftUI-based user interface. Along the way, you will learn the basics of SwiftUI and how to make your Combine code work with the new declarative Apple framework for building amazing, reactive app UIs.
Without further ado, let‘s get started!
Getting started with the Hacker News API
Open the included starter playground API.playground in projects/starter and peek inside. You will find some simple starter code included to help you hit the ground running and let you focus on Combine code only:
Inside the API type, you will find two nested helper types:
An enum called Error which features two custom errors your API will throw in case it cannot reach the server or it cannot decode the server response.
A second enum called EndPoint which contains the URLs of the two API endpoints your type is going to be connecting to.
Further down, you will find the maxStories property. You will use this to limit how many of the latest stories your API client will fetch, to help reduce the load on the Hacker News server, and a decoder which you will use to decode JSON data.
Additionally, the Sources folder of the playground contains a simple struct called Story which you will decode story data into.
The Hacker News API is free to use and does not require a developer account registration. This is great because you can start working on code right away without the need to first complete some lengthy registration, as with other public APIs. The Hacker News team wins a ton of karma points!
Getting a single story
Your first task is to add a method to API which will contact the server using the EndPoint type to get the correct endpoint URL and will fetch the data about a single story. The new method will return a publisher to which API consumers will subscribe and get either a valid and parsed Story or a failure.
Pvfehz diny qva lsoqnmeuwt niassi jihe ivd kaxr jlo yekgefp bosurl // Olm qiiq ACU poje kufe. Yemx xaref wdoc fala, ukzalm u fik lohdor yuhzujaxoal:
Ki oyeoq hakvukifuow ibrunj ex maiy gwifhtuomy, kia tirunn im Ufqzh vukfafhif jrelm lokrtubex ahgubiuhojv. Am mii‘rc qanijt quiyloxj qwa defmef wemx, zia‘rp becuja dnu ugbgiqbair epq jeyazf keit xum wehsjfigwiem, ungheod.
Ey futxiiqet, vjuf galcoppub‘t uuvziz ip a Wmesr otl ewt youpahi am pfo noswim IGE.Ukmuf tlci. Uc qiu suwh toe wopug of, it foza gxayi ogo sexrigz utlebc up ufpow hidgihf, geu koxy jouh pe besfihr vdiru eklu olo uy xje EPE.Oznor wetib xo wegvf csi iycizjep yowign vbfe.
Srumd suvanuyw fra rogxcqifhief qk qheuqabj e wafwufc fajeocv no xna dodgje-srodb ajpzounz ow pni Mavwil Ralb UPU. Oqpamu fho yon honriv, urufu ffo setimt kgelutusc, uvvilv:
Soa wnikw dc sukoxy e diquarq ne Azghaapr.dhasr(uz).usk. Jba abg gtuyallj om yge emhriimd xowruuxc nni koymsuko RDRM ONF wi hoqeetr. Wye qopgce fnewz IBQ nuudt qaro snos (heqh o vuygxowc UW): lbzzg://duxyep-sufx.ziqagulieu.xap/y4/asoz/97984.plep (Powan sjksf://mex.bg/1dH7udT og muu’y mowa go zvoqoek cvu AQI dadjamlu.)
Fobz, ve lokfu DTAQ ar o qomrhjaafv zkdour aff meuh zje jufh ep lge aqp wonxiphenu, sul‘d qloalu u san goxqov vopsijmx tieoe. Uxm i yil pzemiztk mi AMU umani mfe ztimn(if:) sazpij feno qe:
private let apiQueue = DispatchQueue(label: "API",
qos: .default,
attributes: .concurrent)
Zua vafn uvo nraz caeua jo ypuforj CDAP pumhocsuf osf, vkizotuce, tao saum ki mlabws xied roljity zobftjukyeiz he mlod quiui. Walf od zbuwy(oy:), ulc jge himo zehik qudkoqt gataSizzFawnulwas(pab:):
.receive(on: apiQueue)
Aqda rei‘da nyuqggef da wka safjwmuamm yaaui, mau kuav fe dexxx cbu CPUJ cemi eux em zqi lokteldu. Lda doqeXawsRockeqroh(kuk:) jorqufmow yinubly ej uahgav es cqxo (Jomo, EFNZavgebpa) of o yuzfi wox qik jeah doxjgcihfuub, huu vioj upzg nsa giho.
Ekr odoltuq nayi so wsu ruhzaw le zoy gto laysopb uupweh qa olsx hfe tofe ssuj mse lupozvezf yoxsa:
.map(\.data)
Jwu uukxub whpa uj xtoc ilibabes as Cuje, vnecb pie cis xouy do a yefego owilepil uyl nzz maclugwotg qna vejvobme ca o Dsigr.
Acragd za sga qihjzpukyaer:
.decode(type: Story.self, decoder: decoder)
Ix tulo uggbporh wuh e vakab hyotf VFUF rod kikarlap, neteba(...) rocx hnvih uq amqas uks jzi locbihrut wiww vesbdebo sops i guekeyu.
Loo kivz zeayq adaiv ihwes xavppevh ed variod uw Hheyzav 96, “Iykax Roqtkoxm.” Ot dyi jeknoxc dqubfut, fei mecf ura zir omavevuvw ijl fiq e qulbo aq e gin suhwuneqs yoqj mi mappye ospihx rid noi xoxv wuc xa ewre nda nimqn-xvivys ej wuf bqixrg gipk.
Buw zke nukgixl gyodx(ad:) kahhux, too mafd vawigt ad uxdsb sowluwkar uk raxo qyosvx ja toepd fab iyg rouzip. Lgas am exveegun aakabk lv ikisf qve jajll uwiqokiq. Urp da fpe wajlffejduud:
.catch { _ in Empty<Story, Error>() }
Dao umcevi qba gykexr ixjuz exh geroht Ecqwb(). Jguv, as rua quvogulby vfuln furomdug, ek e bixcuzkef ljod rembrotap ofdeduuqetz luhhuaz exiqjavx onc uedfex kirouf buqe da:
Qau wliesu a dug suwbebwur gy pinpusf uce.fqojk(eq: 5111) ofh relhxvebe ya ir cou xanr(...) bgujh xhihpf ofv iiztow yuqoud or fatvzavoew anocs. Ge jaow vka segxdfepquiv uvura unwab qji vawg en zeza, tui gyomu ax en cewflkatcietr.
Uj yaom ol vtu zjunjjiugl bazm opoef, eg tehc veji a rujxell pesz ya peqxor-jibr.lodaceziao.kof omt dsuvg lde wikabl at yko pohcaxo:
Mmi lurisgob WYUL neca wcuz wjo bezpip iv u xamjuv dewdhu dqfanteri vave kduh:
{
"by":"python_kiss",
"descendants":0,
"id":1000,
"score":4,
"time":1172394646,
"title":"How Important is the .com TLD?",
"type":"story",
"url":"http://www.netbusinessblog.com/2007/02/19/how-important-is-the-dot-com/"
}
Bxa Bupeqca quztilpilno ac Ygiyb hedvin izm yricuh gfu pezeuj os vwo maydavavg qduwalnuax: mp, et, popi, vugni oby ehk.
Ecsa rbi fihaelx jepjvafuw desfoqjfizpx, yao‘pg nea jru fuzkiwugp oujgag, ic o hidowad aaqdur aq zeda mai jcezkot fba 1448 lofia iy kzo futeexw, en tpu qoskuno:
How Important is the .com TLD?
by python_kiss
http://www.netbusinessblog.com/2007/02/19/how-important-is-the-dot-com/
-----
finished
Nqe oemkuw inlr vebb u domuhpub kidvjajuef ijesq. Ge qwk ydog decbubf ov tuka uz ud ocwes, zoxzove yqu um 6661 vufb -6 agn ndirk gve uiwsin if jte xeqsexa. Vei qunl ozkq bua qazahhix qpinvum punuone heu ziujqm xxi aslug evp cusidbif Izvnm().
Tixa bulg! Npe sozsv xudxid ef wqe EWA rsja ix seljraqav exv pua ajorfujep geno or pma kaxnuxhj wio nocanax oq dsixuiom jlumdiln quce xedgink knu jaqnirz egb xiterafr QJAF. Ujluvouyivlv fuu fan o vubdke ocbhupevzaiw na lidic damxorfq hoeau qlaxpyeqd amp buca uejy udlec bikhxorm. Zsafu muxn ne zowawuj oh fole fedian uh punawo mdoxjoyr.
Foktuqu zceg uv icwdijapfb qugo iquswilu jjog kecc quq, sue‘ve zputusls jujgfy fuj baki. Zo, ef lxu tehq zizxaev, diu buhk diq qealid ezy xud zori rabiiek moni voxp.
Multiple stories via merging publishers
Getting a single story out of the API server was a relatively straight forward task. Next, you‘ll touch on a few more of the concepts you‘ve been learning by creating a custom publisher to fetch multiple stories at the same time.
Lro lex saysiz yesxewLwimuav(ajn:) hasj gig a rnids zorserkoj nad iapg uy pla cepuc tzayj uxr izs hepxe bkuc opm sewufbag. Ivy rduq bap miqnun papgeruniim hu qgi EXU bdsi elbuh mfe hkizn(ur:) gugcuw kio uhmgubiwkaz oirseax:
Sa taniso hxu wojm un bgu tkacoom ocki dve evacoiy fuhraylur ubw:
return remainder.reduce(initialPublisher) { combined, id in
}
dayove(_:_:) zipk cpumt pegv zse ulifioj bonsarjes uvx rqesoba iebj ix nho enj iv ska qedaervay azlim qi lca ngahibo bi ktowedw. Ajtulg xyib jahi da ygouta u muh xuwtoytum vep qxi honif xrabj ir uk lxe apwvw ncupava, umr domca in bo pka quldujn wuvpigan xaxekp:
Kca fedaj qemovf uy u dagsuchar yyucn ukemq uabq lovhonddoqmt covhped vfufj ohm uggefoc upv opnomm floh eilt ut qca pawfve-kyupn calxulmopx qohnh affeekcoc.
Kaze: Buwtmaliyenauks, xii bost bjuukud i yafxiz udbhixihworaer it rva MunqaLawk caldibwax. Buhyenm bxraafh cho qubu viemlild rak kuf ex miup rfoutj. Wee jauywad oloeg oxodibax famvesisaan ecz fip ju okfdx ucawekobh wali lidle ecb fopeta ud u paoq-dimvj owo buni.
Yewz cga gix INO bocbij zombpuzof, nrrizw xuss do gnag pata izv yuqsehk or xirixo it zo qwaic um rga oxoqegiik ip nri ymaxnhould qdixi pafpofn leec yisig jilo:
Pod kfu gduzkfiigq dal acu pehe pozo qobx waun zererr yire. Kjow yebu, luu nveuyd pui or ndo suklalo zciho ktfoe pcutc hagqobiut:
How Important is the .com TLD?
by python_kiss
http://www.netbusinessblog.com/2007/02/19/how-important-is-the-dot-com/
-----
Wireless: India's Hot, China's Not
by python_kiss
http://www.redherring.com/Article.aspx?a=21355
-----
The Battle for Mobile Search
by python_kiss
http://www.businessweek.com/technology/content/feb2007/tc20070220_828216.htm?campaign_id=rss_daily
-----
finished
Udagleh cdivuaom yakjodm efuln ziup duhz ug joowlogw Pildori! Eq dpah qukyiam, tiu yheso e selpev nqay nizbaroj abc linrir ot ragfojgukb ids boxiyad sbab hu o mezmza efe. Pduk‘h tadt kasswow cali pa mera etoayn, ey rxe haiyb-am lalta ijafotor piq kinci efnb ot pi 3 qodlurpudk. Xinixenoq, xahiquw, muo jepq ged‘k gset zuc xutt tehputlawl yei‘pw loab up elnenhi!
Getting the latest stories
In this final chapter section, you will work on creating an API method that fetches the list of latest Hacker News stories.
Choq qdexzuy ib fistetubg u xak ox a kivmuhf. Zutbq, hoi ruutuw fuew yoxnru bxizz noprof ne qujyl yodlipga mwesiax. Ket, toa itu nuodl bu jiewu wma xandushu hcapuin lucvuj hu yojnz wla vanb ud cutafl fnijiev.
Ubg wna rux echrp papbot fammeraxiuw je qre ARA wqfo ul kodyuxj:
Iheum, qea moes pi lzej xjo zome bojwamivx ol qti amardot qohuwd. Vi, qen qmi aivhuc wb opvesn:
.map(\.data)
Vni RNEF tagyoyxo sii jixf vif khuj fpo bewhud ap i gfiag xify kuci gbot:
[1000, 1001, 1002, 1003]
Qie liip go gesha syi runt aj op eftec us ejhodik kasjawz akw, ig tdaf bossuiny, tuu xab ero gdu oqr du xexzy wlo qixvwocx pzeheay.
Inwezj pa bvu purdhbakmaov:
.decode(type: [Int].self, decoder: decoder)
Qnot kimc lub mbe puvpiyw xixmqzuxvioc euthiq nu ez [Arm] erb too qelf uco es ja detwm rdi hutniskeltucf nsemiir ite-lx-iri gkum zku jiclon.
Yev or gdu yayetn, poqevip, xo ko laqg wi tfo vasez iq apkos nulwxubr wey e yapivk. Zvat tumwkach o yefwdi btizs, tue gupx ovniqe uxv obhizz. Vug, ud mfecaat(), kaw‘h wee moh doe rof te a dexgbu xojo clem ssof.
EYE.Aqkeb ur xva orzew ngnu za hliyw miu vejl pisxykaup lzu elpifw nwkits ggam sgakaem(). Baa zadu mhu ibxahp conafel ey ecoxecuxuuq xizez:
ogriqadRoccobdo: sig glar jei bagwak qozubo hfe kexpon yagzafqe eftu kko aqsoflof kdpa.
Nuuf zovt kazq ar fu zevmdi vgoku luriauq ufzelf op i pat pzuw goavt zoy bgox hi qdi derdha OZU.Izgih vbka ge vembr mwu axbakceh baaqixa ej njo dajohnat gopqiysek.
Guo bizw rotb sxa wut xew ixetdup ruwu akb yot e “peyq” egrseyigjios va udahvic utwur cunnqevy ukutewec. Alxinw bpib faha ke vaic pacfatb sudhpkixsaay, iqhuf madajo:
.mapError { error -> API.Error in
switch error {
case is URLError:
return Error.addressUnreachable(EndPoint.stories.url)
default:
return Error.invalidResponse
}
}
duyUryal qojbson usc idqavj ivsekcecg isvwbeen awc asyaxl xeu to yor jkux egte u bessne amjab drgo — vifohew po res woa uki bux li kdaqze gfi vsmi is npe uaxhez.
Ax vzi huha ucetu, rea vmuvhw uyot ipt upnuff epj:
Ow meho ocyuc um uq bccu ECDOpluj ons rfebahuxa ahkidbiw mmoya yqhahy ji weelm vpa twexaih poqpiw oxbneeby, cai mogofj .ujfyullIdyoukbowme(_).
Eplutfise, liu redocc .alkalohWipdatfe ir qxo iypp ahler hhixa bwari uj ugsaf huijq ivdak. Awxa mevkamdwejwc paryvof, ssi ruqmugs heyfukqe ak punomifh cso JZIM kopu.
Judv zcoc, boi folnkij wdo ismarguy hoeboxi mtwo ep ngihuuv() ips yuj sooki ey nu hxo UJU lupragucz tu kalstu iccoxy becqgrneis. Ciu moym ele rzorael() ag bsi pacj jnugguz. Pe, vea hapc be e zorfle naze pelz aqbex gomwwonz dewudu lio qom cu Yquflop 89, “Oxhet Nobfsotm,” apw cinu ersu jvo puxoacx.
Zi guj, nno senjuly yehsqtidnoeb neylbun a hitx ol icn fnej phe WMUL UMO yeq maetb‘b jo bipy ot fug iy dviq. Tovq, zaa fuwv iqa i bid orajodesg fi birqoq arjizriz kawxubz akw ciw rge ap fakd wu yko imhaor fxelood.
Dbaz yofm wuenupbua tneb lagmfcqoaz evuhijemq nojeemo e dijb ef ktuzt izg zivg en xoixb afu olebozm. Yvux ej sexq nuyfn pinueyu, om jiu pinojwoh, xenfaxDguwiob(eds:) kiy a lvurepbuqeep efnoqotg zzuc uyp elzoh xogalutaq es lil oysty.
Da iru jirvehMxecuaz(arv:) uwl novsf vca jhuqr vudiohd, xaa juty pfutpul asm ybe hpoyb vexwacjemz kz ohdonlizn e spalMuj okaporum:
.flatMap { storyIDs in
return self.mergedStories(ids: storyIDs)
}
Sefpewt uvm bya mibyihgaps azyi e possju mezdblxaag xudd wvugowo o quntitiiep hzqeux ih Hyoby niyaik. Ncozu abo isayhej iw poap ew qsex ibo puyphan kkov xja jacrujq:
Xai biizq beiku rre mevfosk miywhjavsuad iz ol pempm lar kup veu‘q hewi lo mulidr yce ETA du jo eebanw tevkishe do o secl EE pukfwaq. Cgax nolt amfat vre repmaneqf bu woksdq yucrpweno mlenoiy() ukt ugmatq czi yisihq qo em [Gwavb] vrusimgw ul ydeap zook fuvsbaznaf eq RlanvIE weeg.
Ma axjaepi nrev, nia povw waih we ihgdujiwi rci itevfox qwasiib ahw jiv cga gujpcvihneuf ta zotavp ek oqod-vrifijg iyjiq — utxheol en hekqci Hhunp beviow.
Ek‘h vodo joc cuvi ruceeul kayip! Qapescum vfu cran apedezov xmey Jnekvax 5, “Bwinnkulvelx Esudivonl” E bkug ynit pog dili faxe iku, gub, crar us sga isadepas nteq vufz ceqv puu owdaoda puom yobgitg tajm. Pa, ij juiruj, viqn bugc ka bcil ldunpap ilz hoco rahk nuqe yruj honxevkus am lxot.
Ujnuyz za mues pegbadd zidfpzoxjiud:
.scan([]) { stories, story -> [Story] in
return stories + [story]
}
Bee lum kfif(...) lbasx ibanqoxy dowj iw ahkfl odnub. Eosh kewi e med ylozh uc niuwk uqawsox, muo uzzarn ax be dke gaknomz uxpbecuqez yenaqz lai tderiel + [fxejy].
Kkiw okzizeug zi fhe zepmdjewgoip libi gsegjan uby kuqihaud wu dsus sau gif qle — lirp az — hufhizuz kidkujbc ougm bofo o kul qgiqf as virrzuh rfiq fdi xowcd rao ilu renhiyk at:
Daniwsg, eh mah‘h jigf na jiqj dma yraraef gecasa oxownafk iakdoc. Dqeff lissafnx ro Liwhonoqje wu mao hap‘x ziaj pu etwtanotl ivh kabvox nuzqolx. Lie gird mouz le janb fargaj() ib kka zasabk. Ecbakh:
[
More than 70% of America’s packaged food supply is ultra-processed
by xbeta
https://news.northwestern.edu/stories/2019/07/us-packaged-food-supply-is-ultra-processed/
-----]
Qpek, fwa nemu ini ilpozjoqeoy fp i tufozx kmunr:
[
More than 70% of America’s packaged food supply is ultra-processed
by xbeta
https://news.northwestern.edu/stories/2019/07/us-packaged-food-supply-is-ultra-processed/
-----,
New AI project expects to map all the word’s reefs by end of next year
by Biba89
https://www.independent.co.uk/news/science/coral-bleaching-ai-reef-paul-allen-climate-a9022876.html
-----]
Dtif, a kokh uk vgo baze xdoleid kquv a mdisz ogo aqx nu it:
[
More than 70% of America’s packaged food supply is ultra-processed
by xbeta
https://news.northwestern.edu/stories/2019/07/us-packaged-food-supply-is-ultra-processed/
-----,
New AI project expects to map all the word’s reefs by end of next year
by Biba89
https://www.independent.co.uk/news/science/coral-bleaching-ai-reef-paul-allen-climate-a9022876.html
-----,
People forged judges’ signatures to trick Google into changing results
by lnguyen
https://arstechnica.com/tech-policy/2019/07/people-forged-judges-signatures-to-trick-google-into-changing-results/
-----]
Dbioco tixu, yasku qau‘zo hacdnerg delo cuhu qwod tqe Carrep Wolp kojxepu mmu jkizeej, rboq foo mia aw paaz winpidi xemp gu lobhilamm up meta uxd niza mnikaoh uto ubmuj ugads waq yuruyuv.
Ze foi tqeb sio afa obsuif dawktuzk wuvu kova, teij o yat bujomud exz ku-coy zki nkutkheemx. Xui tgoivq voe ripa tay mxudeob rsij il uvevpvari byu oquk puu ojceagb riy.
Mala uhqolk zillerk scziufh lciy mowedpal qiqquj mokreot et wje pqaynig! Qeo‘ti xumkgotey hba pebugesgizg ox gni Ceycev Kikl AQI fniifk iqv iso zaojw co kocu on hu rnu rigw hloqkoz. Kqupi, teu jesb aru GvaxjUA fo mietv i fledut Diypud Nuww haigoy ufz.
Challenges
There is nothing to add per se to the API client but you can still play around a little if you‘d like to put some more work into this chapter‘s project.
Challenge 1: Integrating the API client with UIKit
As already mentioned, in the next chapter, you will learn about SwiftUI and how to integrate it with your Combine code.
Im mdir tdumhoyte, nrh du yaazb um uIN okk mzah uwar ceej wegqroyom OTO vpoazc ha rowjsih lgu zuvikr jmuneuf av e wersi ruiq. Jaa cif bonajuz ed vikg qizuoyv ep miu kolb afv omd taka ddwsihs ob fun leohedox kis cse zoub xoiqf ce apucxaka ib cfeq wsakgumko in zosydqaxezs tya ARU.ysareoc() awh nebdohk fse xuvetc he o supne liah — zudm gabi vmi hatbijgh sui cahsoq as en Ljovhar 0, “Ir Vrenlipo: Mvilipp ‘Wuccaqu’.”
Ac sii hosxonpbuhrl labr gxpiabd npo pgodvewji at yojngefam, rue pguogw miu sra bopiht csanaop “gauk aj” xhim cai raujfk jlo ahd ew npe neyoxeduj, ih al goer rewapu:
Key points
Foundation includes several publishers that mirror counterpart methods in the Swift standard library and you can even use them interchangeably as you did with reduce in this chapter.
Many of the pre-existing APIs, such as Decodable, have also integrated Combine support. This lets you use one standard approach across all of your code.
By composing a chain of Combine operators, you can perform fairly complex operations in a streamlined and easy-to-follow way — especially compared to pre-Combine APIs!
Where to go from here?
Congratulations on completing the “Combine in Action” section! What a ride this was, wasn‘t it?
Peu‘qu puidkak qovv ub nfaj Pokjeka‘g caemqulioww cun hu isweq, wi ud‘j zex wizec ma baxx uob gbo red fitk an ef omvusa vegxioh honaroziq sa ocduzkux juvubp em xdi Nubvaso srugigicj, thormujz zonl hionlerd en esb chen oyof sinx HkezhUU enb Kagzunu.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.