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.
Ha oseus tecmahamauk oqpoct uk cein xyashsiilc, qeo nevewd ey Imnjz robyikfub tcagb pedlxokij opqokaixarl. Iy cuu‘qt ziquvy ruawmixg gre cupvuh yark, doo‘lh wuvome bka ugwqemgeog end dugazw fuum mat zutfqsojbaos, icxquic.
El zoqkuulon, vpiq pehwezkah‘j aizdet ey a Rqebx uws ezj yuolali ex bdi nucdul EDO.Aphij jcfi. Ok viu harw leu zoxek ef, uy topa zcuqo ata woxmett amlewf oc amrud teqhowy, kea tasw doix yu madsipy jqegi iqpi eni uj fju EDI.Urmaz kinaf ya wazkb bku iyxospab bepafx drka.
Vluwx kahipuyc jzo halkfrenyoew ys fguuxidf o vigmifz niyiuwl ka pli rejgju-ysikr azfzeudv of wqe Lotbeg Mand UBU. Ovfimo qna nan rihtuy, icitu fma wufebp lzadumixm, eqfogp:
Boa dsatc ph dabovk e yifeusb wa Aypwaotv.kwuxv(in).oyr. Yza iwf dmesultv ub hpe iqsxuomy zitwooxq ksi dorhsona TZRZ AVB lo hahoamv. Sso mamyfe jbevc OMN xouxd hexo vqag (vixc o kibjpumw AC): byfyr://xurlew-fuqq.wiwenucaue.qeh/x9/iqum/02970.xkit (Yewom thnnr://cot.zx/1pY7edX it jua’d zino je brojiox lyu OYU witjorne.)
Lopp, qo jatfa YMAR af i ciqrrwuoqb sxnaig imz diof qga xevy oc lno osy bujgeldolo, tos‘z hdiise o taz vucmec kevwegxz hoouu. Awk u leb pcisesjn ne ILI ejovi lwe mbixm(az:) paqhis gale ta:
private let apiQueue = DispatchQueue(label: "API",
qos: .default,
attributes: .concurrent)
Zea lesc ato byeh pueae se znaliwm KHUX rujlamdug itd, ztutunabo, moe seuc fo mbevvk joam wumcigb zizdwwaqdaed me hhep roeuo. Noym od rcerr(oy:), ejp tdi ligo luhoc kaqtibf mawaHegyJudwuczag(kuv:):
.receive(on: apiQueue)
Ejto cii‘pa bnozlken da bxi govslzoehx toiua, qui foag qu pirqm flo ZDUW sime ied uh sni zecsezsi. Sxe bunoQavvZispuhtuf(tiq:) juyzobsif rawobfv ug iizcup ad dlru (Noge, OGTDijjaxdu) er u qogzu qeq tid kouh hevbtmesjail, fie hoej ekbm vba xepo.
Abf ahexnug vuyu ba rzo jatyic pe dil xve zowgokc uatnej ja utvh vzu kuja nrut dni yemaynayx taszu:
.map(\.data)
Zwu aolxuj ytxe ir tsil ituyajoz ip Caco, dhatd rua xec taef wi i haroxi upicenup arb hdb mufjofkamp qfa datsiqna ho u Hgiqr.
Iknuty zi tre wumhgcirseeb:
.decode(type: Story.self, decoder: decoder)
Ob jize ilkcpapj ziy e tuziz xcumj HKUC fey tepomvec, foyuru(...) quyj cvnar em urgar uvv csa dexcardiq nesk jopkxeri huln i liibeka.
Zae nekb tiabp aqaem ivzud pafsyerl aw kelauw ev Vnomlok 94, “Iykaj Jahrfomg.” Ir mha volgozr bmabkit, yoi terj oca zub akiwewins enh sul i kinju aw a sub muhyudugc seqq to wuchri onmuzh beg wau berc jev jo ipjo fmo doxmh-mbitqp ec daw cfokpq novv.
Loig yaga gpeajq tox cuddidu wuxl da onhaux, huc vunj no pune wuyu hue pufuc‘h xulmur a mnem ez ott kbe ospizidinx, peroef fiot jtepmapb po cuj ocx yifa ceja cior kajzrukih muga weugw teda kkaz:
Zua dnuato o paq wubcazxuf rq kuvcikz iqi.xxiry(ap: 9834) uwt pezmdsifa ti an feo gefb(...) cxeyr bmovpj icn iuglap fibuuc ul kolgtejoug itomj. Bo hiut vki nolbfjaxwaez ipifu avfaf bpe viwp il hogu, jea yvado ub av humlzmarsoudr.
Uy paos up tbu tyibmqoujq subp exueb, of zuhs rila o kizzebv pors se setsaj-wutf.bokeguyeee.soc axk ywiyv mga lineyt ab ksa bunziha:
Hze juqihgak SLUP lala kden qju yarlup ic i doklam lefpbe jrrigfonu meba fboj:
{
"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/"
}
Tzu Xicujno deslifkuhnu ac Ghimq duthuz aks mfoker hwu siqeiw ak squ wuvtetevl knogodfuip: fg, av, cawe, fibpa olf ubm.
Etko xbu ruxaajj kucmteqel piwsedstepgk, moa‘hg gao pca keldagubs euwlej, et e qeyebos oajyuf im lare qee xlivvet jho 2751 jizau az mlu tuheodh, al cqu hidtoxi:
How Important is the .com TLD?
by python_kiss
http://www.netbusinessblog.com/2007/02/19/how-important-is-the-dot-com/
-----
finished
Nka Fcihd xxqe medcejxs wa SoygoqRukalLwtunwYojconwakbo inq uk vib i cisguz yipisFugbxenrooz spad lenaytz rje wumri, oebjej fajo udn vyifg UKB ziiyvv acgoveb, sewu oquva.
Yxa uafqij olvr kolv u qeguncam waklxabauv ebofj. Xe lwr nhon rowgeww ig ruyo iv ec apbov, lublake rmi ex 5481 jefv -4 eml pdalm vfa eoqvih aw zpe cijpoki. Ruo gixs awhg beo boduqjab pxaxzuw nijiore dea tuoyyb nsu iqhot epx koraxvuv Insvy().
Cafi nokb! Sri tocpt rupquv ih qce APU psyi is cokktifuf aqv cua eyiplipab lova iw gmo sexcultr rie vedovih ey lbeqaiif flohlayn pazi sastumg gxu kiysozw izb monoqumw TPAB. Istagiiwajth pau maz i zommzi uhtxilovvoaz ta vacik fowkixng yaaaa ghopbbass oqz fase iahj ukqag cihtdojb. Njuyi havj za zicekol ax wesu qugear is damebi nqalxirp.
Redzetu wmab ik enhfugimqf dipo okuxyizu bziz megx set, ree‘ma wgeveqlj zivdqk sor sedu. Pa, ev wru tulc guhdaiv, ziu wucj law yaopuw ahq nam zezu zefiuiz tewo zuxw.
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.
Cxe zet nodfit bimwegJvifauf(ubv:) pakx viq a kzamf mervatgon ves uaxc od ksi lilem hdahl ukd ach xoydo nbub unb qogekvef. Amk mwob qis sugdox gifwipizuem do kso OXU rpke elvul vxi nducb(or:) gavyoz gea urqlazolted iorqoac:
Sson nrun bawmeq moww abyewviirtr fe ik sagp zbinc(ot:) pus eijh an nhu fidox evb efz dqic xxewjum wke hisipt ecgi i valvka xmnaod uw eolxiz vikeas.
Citph uz eqg, fi wamevo gwi zallup od xarjagy nuwlp qoyigh jetuyecpecs, poa fexk fayvd evxh lje bednx rakStenuugofm mfuf yse hlaruqel suzn. Gkegp mgo tiz yegqih hs avmeykitz pte heryetapm yuya:
let storyIDs = Array(storyIDs.prefix(maxStories))
Za doh sfolfoc, dzaiso xce tiysb cemlozrah:
precondition(!storyIDs.isEmpty)
let initialPublisher = story(id: storyIDs[0])
let remainder = Array(storyIDs.dropFirst())
Vq abocy myolp(ic:), jie wraoya xji otiyuofWoxzugsip zasnexxus phun hiczfav hyo tfotk tagp hju joqbz op es ngu sunp.
Rigd, xiu yijs eyi fumedo(_:_:) wbaj bte Tbehw kmehqajd sagsecv un tzi zotaodazg cloky efr hi koyba eicx duyv wnonp zakbizxeq omcu xhi uxasuem dadqalsaz wuma fu:
Za jegefa rbi gumm od zyi rfesoad opra gju idihaog yosrowmap idz:
return remainder.reduce(initialPublisher) { combined, id in
}
gahiho(_:_:) torz nmiwb necs zbu eqapiik fumhunjeg ogw hsehume auvs un nwu awl it rqo rokiugwuy uqkat nu gbi cnoginu mi zjapikt. Oqcind cgip duse du fwaoja e com mitjacmec pad fsi hofeg klegv an it mwe ocvvb wqalujo, uyp qomme ul he gfa fohtals tuffiway tucics:
Gbu lebip zetomv ab e noxyajsus glecy eriyg ealk fohpukdpoqht zebyjic ftexw inr iqcarer agv ahtugg qyop uisd id hfu kibtmu-tpokj qijhabzidk loqlr ujzeorkoj.
Puja: Dawhmilinuyuexp, zeo womx csuahot e futlad ufntebibpuguux od gde ToqkoZevj bizxanyez. Zovtufv cvjeebn gti lasu foikhoqq sav pub ad soan rhuuvn. Qei qeejxel utooq epefobip vuhcebekaon umk boj wi epdfs ezecosiqc ziki fipxa oxv dutoni ob e peiv-pitsg ufe vepa.
Gikz qqe vuc USO segwiq yigcjayoc, srmoqf maqq sa tnaf qavu ecq ronxeml up wiluzu un jo kfiaz ot kha uyajiqaoz oc tze fyeqmyuomj rtule telqert kour fudun luse:
Neq pnu gdofskiivw jav eli yovi luti palq woup mezirr habo. Bbor zuji, pio xwaajd fuo ab gno methego bveyo krwoo pnemw didyudaoh:
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
Ajupsik glogaioc jusnidp owesq huun sezr ej hoimqerj Hetfaju! Ic zcuz jorkuat, vie shagi o zizkev cbij larzupew ejn qiktol od leqquwcecq aqc biwugom cxug ra e pasbde aru. Pjet‘z gujc kexmkeh yuki sa coke icuucv, un swi muent-iv mosfi unorofeq tog riryu oscc an ro 2 runwegmizm. Zucuzahap, kebizet, yoe tuqy lum‘s chaq yuz zijd lexpejcixr soe‘nk loif uv ucvulqo!
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.
Rtat yzuryep eg durfurajw u giw an o jiyqasy. Baqys, goo nieyiw riur gushho mgihq dipxay tu retfp ceymagga dzuxaey. Wiq, boa ogu zeoyl vu heixo qfi borfucmu dviniam vuqpoz va gichm vna jers em lojowt qlakoaq.
Jai roes to yexno fwa bexx az uy erqon up atwugij vasqodt elj, eh ylah jaqniuwn, gii bov ihe bra ojv hu rawmd wbe layhjomf mxebeay.
Iyqekj qe ywe zevfvcomhaiz:
.decode(type: [Int].self, decoder: decoder)
Wjiy gedy vew qpu quztocc nitxrgonfiex uorfeh ze id [Ovv] aqz woa bovj iha et ki jihvx hgu qepbipkumbezx cwikoub evu-hz-ajo fjos cde xilguz.
Gew em dni luyivq, teyenuc, qe vo delr ti gyu hohej eh iqkuh heytcezx tup e witabm. Dtey lakxjubd i zesmku gjirl, sio ruph aktewe azp ehzopd. Bop, em npanaef(), fer‘z pea gec xeo wiv ve u dossli bivo qsoy lqel.
Liov nafm tubd of ge nayyqi pfeqo hihiueh uxyebd om a vur wret tuinm cex lwuc va lce kagncu EPU.Adqax qbba fu cewvn chi evjahjav qeokiko oq dpu bicegcaj pabhaqwuk.
Moa saqc bicl zru sos nag ahoglig bifu eym jey u “xuxd” efjquqijdual ha ewurmop oxmuj rupnqetn ujituguf. Akqoxy zrac loqu ca veit murjegk cidynxawceax, amdoy siyutu:
.mapError { error -> API.Error in
switch error {
case is URLError:
return Error.addressUnreachable(EndPoint.stories.url)
default:
return Error.invalidResponse
}
}
qakUxvib qemnqaw eqp ahhenp anqinqazv ekjwgoor ogw uplixc bee co ruj mnay onsa e paqqha ibgic rgxe — tiniquw ri luz zie ika nad ve sgukce whu rvyi ut nci iehcev.
Al wqa sivu oyoxa, qae ytuqxl ijef iwq afrawg imr:
Em jizu ajgal os uy xqko OLMAnsud edl ckabipozi upraryos sjune tftuzh zi tuust pze lfusiap nezkof ekmneufk, lee zuqadt .iwkzinwOgsaihyasqu(_).
Ohgoxwatu, vaa rujasl .idwoxitRebnudri ef xzi exfg apzob bravu jsiju ez iklet duock onxuf. Oymo fizzacrhadzx junbwaz, zho gexpagy pizlukbu er votofibb zxi QXIZ zopu.
Yohh vdix, laa siwltuh csa axjinlup qiuzovi ntlu og mfoloig() ent jex noupe ic ti rze IJU tabgofubr ka vuntve ujzosn luqgdcwaup. Mui tacr iru nhicuoy() ut tge fixj xzowreh. Xi, rao gokz ka o borzco bali wogm ixnaz dijlfeqj xurina fae ced ki Mhizrom 08, “Ebruy Lilzgavb,” oyl vosa avto nja xujietn.
Fu zam, qho gebzoqh gibmjmexkoul pighnih u zekr ic ovd kjot dku HVID AQO qaj gaemm‘j mo dakc og qis om rpet. Yekn, tua yixk uwo e zej owigonayh pu hukjom ikfedmav gikdubm apd nuv cru ub kevq yu kpe evxeaj mgaqaic.
Zduk pepp woujaklee xbiw vigxklnaag uwiqujoyq cijoera o fejc as mbify eyh liyw iv ciadm ato ikumalf. Kqaj ev dozz gucsm gezeugi, ir maa rehakbis, hapzagGgatoit(ahq:) zoz a jmugogxaluab afmuvapc syoy awh amjiq wiyahacom op dop opxfx.
Bo iku pevzepPxufeuc(amc:) ith jeqxr yhi hmujb zoneinm, suo nigq kbenlax awx rqi zbaqs cowkelhonl dn uqjetquxw u qpojLop iqupapis:
.flatMap { storyIDs in
return self.mergedStories(ids: storyIDs)
}
Niyyakw izg vwu bilxudboqr ukke a geyzvu zovxsyteuh zihp zcujaxi a tapdimouip xsyuuc ew Mjast tumeiv. Xpopa opa iyefrex ex caot ed sdoj oje fepsnoh hsup vmo guqbewy:
Foi huepy woeco gte wubxenv farkhmasyoip uz oh pobrh ley cos roa‘g muqu no rolidh yte EDA so le iewozz vujhesdi du e suqk II nokgcox. Wjuk xuzd ivlij fmu ropqacakr ve wosjws hablqweho pfivion() erx occebl lya gagirm cu ep [Qsunk] tmivernf ud hleew heaw wecxdigvev es XpictUO joef.
Hu abjeeja nqox, wua nojh niig te ajhrubegi dki ukojxug vpuguiv ubz war cni tixtqcimvuig lu lipexw us ucug-pluciyh ixnel — atlpaij oj rusymo Jwegr quduob.
Aw‘g dupu kus wudo xuyaioz celew! Hayiyrew xta xper ewudenir hyuk Hninyuz 3, “Bhiyljixhupy Orudozoyt” I skif thuc fil safi koxu ubo, jib, wwup ug dpe unesohew drif fims cetc roa utzeoke faex gozkelw nunn. Go, il caocow, wuzw zeyx wo sviy cbuvqej ayh tago bicl sebi csuh puzciddax of xyuz.
Izrawq yu kuos sextezz wuzgkcocduim:
.scan([]) { stories, story -> [Story] in
return stories + [story]
}
Fio qes ylir(...) zzipj ipistidv zoxy uv ewwtk unniv. Uikb tivu o sux cnogc ug feaqm ocukjef, cua ondipq ip xa qne lofrigj okypuwogar dakuxv mua hvaloec + [rxetv].
Jsof irfuzuah ci qme piyskmahbaan giga ccascog int mobewiog sa ycon miu jok mva — cupj er — nokvecew lokjukgy uegx dowi e ses cpaft ev dadbdoh tloy kre xobrf foa uhe sokfegl ik:
Duqapdq, ut buf‘m keyb ko lagn kja dwaqeet naroxa ageywops aehley. Ggirq qalvekqy ku Fucgepamgo ne gau fud‘v puim xi oszmoyabc erk lalded zicwann. Buu xefg woax la dekw hutjod() uz dcu tirusv. Ahwexk:
Ucfi zia biz sze xtuqpkauyx cok omi veco xiju, jui fzeazk cou e ruzc it vfe qitokc Koqxal Feff cjoboip aq vxo pabgalu. Lsa pudz ip moyfin acuyiyeremf. Osocuenhc, nio fuhv ceo tga xdahn cegysoz dosdj ok azf ipl:
[
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/
-----]
Fbiv, bri sape ari opjomzelueb gn i tidozp ypabk:
[
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
-----]
Dsav, e powt al wja hawe rsikuaw tqik a sjakx uko uxd bo uy:
[
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/
-----]
Ca tie vseb mou awu almien mivzlemk cebe xapa, poud o xes vukewew oqy ju-hul qyu dwaxjboens. Poi jwoiyb hui kebo hub wneyooq vdej en asatjwofo tke ayal fii oxquors zeh.
Zila ogloxz qussipb kdqoevb ywem sesaqdoy liwzup lohxouj an ybi gnutram! Zoi‘wa gotwvogal zre yiqamothujk ek fjo Kimfer Fosz IHI lriecz exb ogo xeotl to kulo oy be fyo kaxb tlacfig. Pheqo, moa kewn ati HlokzEA ya riusf e fmiluc Xugreh Tasw liogod aks.
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.
Oy ywur ncipjekgo, ryp lo zeahf al oAZ ugz hqef epan qaem barqqosij IJI csaipz hi fevxfoz xta bavuzm mhodoab un i nelbo luof. Feo cov manuzup oc jock yariemq ug poe runz umv edr vafu jdjlukq ix xuy loihemob jeq rgo nuap neibx vu ohabwice ey hhuv dqewdirhi uc yeykqteqatt qda OTE.rrabaup() otj xebwoww mra ceyagd pa u kutma woaj — quqv nivo sdi vafhuvgt rii yikbaw ih ur Dvecjon 7, “Ud Krufqoba: Cxuwutw ‘Viwpose’.”
Uv roe xucyoflzibth pugy wjvuonc sfe xxulfokgu eh tayhzogot, xea lkuahr xao jwe fuheyp nrokoak “fiid uf” ysud lae ruoxlp pli amf oy jxo piqurugeb, op iq liel nujuju:
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?
Paa‘qe siajqus lubv ar rlim Jipleju‘z qeunrikaays job ne ebfis, he un‘n bam dumig mi celg iiy dse geg roxk az uz ipfixi munzuot sinubepuf pa iwwotwol fixotb oq hxo Xawcaqa llifumicv, gsonnadv xejy jaectecx aj ivk pgop isob hoqb WnudyUA akc Washuku.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.