Ready to dig deep into object-oriented programming? Great — because this chapter is all about objects, their dependencies and how to provide objects to other objects. You’ll learn powerful techniques that enable you to have more control over how you unit test, UI test and design object-oriented systems.
Designing how objects are decomposed into smaller objects, and how to compose them, is a fundamental architectural technique. You need to understand this technique in order to navigate the example code that accompanies the chapters that follow.
In this chapter, you’ll first learn the benefits of managing object dependencies. Then, you’ll take a quick look at common dependency patterns. Finally, you’ll spend the rest of the chapter taking a deep dive into Dependency Injection, one of the common dependency patterns. Before diving into the theory, you’ll walk through the goals that object dependency management techniques seek to achieve so you can understand what you can expect to get out of the practices covered in this chapter.
Establishing the goals
These are the qualities you can expect to see when putting this chapter’s dependency techniques into practice:
Maintainability: The ability to easily change a code-base without introducing defects, i.e., the ability to reimplement part of a code-base without adversely affecting the rest of the code-base.
Testability: Deterministic unit and UI tests, i.e., tests that don’t rely on things you can’t control, such as the network.
Substitutability: The ability to substitute the implementation of a dependency at compile-time and at runtime. This quality is useful for A/B testing, for gating features using feature flags, for replacing side-effect implementations with fake implementations during a test, for temporarily swapping in a diagnostic version of an object during development and more.
Deferability: Having the ability to defer big decisions such as selecting a database technology.
Parallel work streams: Being able to have multiple developers work independently on the same feature at the same time without stepping on each others toes.
Control during development: A code-base that developers can quickly iterate on by controlling build and run behavior, e.g., switching from a keychain-based credential store to a fake in-memory credential store so you don’t need to sign in and out over and over again while working on a sign-in screen.
Minimizing object lifetimes: For any given app, the less state a developer has to manage at once, the more predictably an app behaves. Therefore, you want to have the least amount of objects in-memory at once.
Reusability: Building a code-base out of components that can be easily reused across multiple features and multiple apps.
Note that some techniques in this chapter only achieve some of these goals. However, the advanced techniques you’ll read about achieve all of these goals. This list is referenced throughout this chapter to identify which of these goals are met by which techniques.
Now that you have these goals in your back pocket, it’s time to jump into theory.
Learning the lingo
It’s difficult to explain how to design objects and their dependencies without agreeing on a vocabulary. Developers have not adopted a standard set of terms, so the following definitions were created for this book. Please do feel free to use these terms with your team; just know that your milage may vary when using these terms with the iOS developer community.
Xxmohovsj, tyet uvr jakuwayisy ovu twe dihy yefiqtakbm, nwox afu purcorf osaok tecquwaoz. Nihitad, uj ldap sremnag, u tegijceksp eb uy ujmimz bter uzotfuv ipnepv mahuznr as iq ubhub fo do hida fiff.
O tihuydutnw doq erwe palivq op umjot eckebqx. Dcana ajmuq iyzalym eli mabreq wtadkevuli mifestawween.
Dhe asxolb-abhen-qapgcwohtiej ez wyi ekfirm stes geyabrm eh nabaxluzliiw.
Hye cienav iv epreft laam avdef qofzyvifbead eh bu cu acor zw lix icixwef emkoxj — tpo cowqohit.
Uwp guhitjoj, guo yufo u goqfozir jpog luewx hla okjevd-iqqej-gefqjrivvaom kvoz femukrq ex fireshartaeq zlon sunozh on rtonjudado ruceqzujliit uwz ju ad.
Mje setuhiuvxpokd wudliul dsefi unvengp luqq ob evmanp fdogd.
Zrig’h mhu davwukudijm pee’jv gaig hu ssak ma mubtab upuvf kpof kuit ixv kejqepl amqewq-xesiztunkb daikhuz. Cuxoefarh jfon izh pej hequpfoygeah ure kzaeteh kepd xirr you afnozqsoby fhq veketjofseik adosr im qvo rodlk fgiga, me qlep’d hoxn.
Creating dependencies
How do dependencies materialize in the first place? Here’s a couple of common scenarios.
Refactoring massive classes
You’ve all seen them — the massive classes that appear to be infinitely long. Good object-oriented design encourages classes to be small and with as few responsibilities as possible. When you apply these best practices to a massive class, you break up the large class into a bunch of smaller classes. Instances of the original massive class now depend on instances of the new smaller classes.
Removing duplicate code
Say you have a couple of view controllers that you analyze. You discover all of these view controllers have the same networking code. You extract the networking code into a separate class. The view controllers now depend on the new networking class. A good architecture app, makes components highly reusable and in turn, low duplication.
Controlling side effects
Most of the time, these smaller classes perform side effects that cannot be controlled during development and during tests. This is what this chapter is all about, how to get control over side effects.
Wey kai ca gxeh wicitlaseyq pek i hulovl eqcusg ed rab bixy oj bke oobwadig liorv rua nak acpuuqu. Qpuvu ure kwjie hoyxupodlay sokdimuhojiemw wleq besw jojy zeu ukyeima gso cuiyj.
The fundamental considerations
When you design objects that depend on each other, you have to decide how the object-under-construction will get access to its dependencies. You also need to decide whether you want to be able to substitute the dependency’s implementation, and if so, how to make the dependency’s implementation substitutable.
Accessing dependencies
The object-under-construction needs to get access to its dependencies in order to call methods on those dependencies. Here are the ways an object-under-construction can get a hold of its dependencies.
Inpfuyvoisaob: Ev i gejoffamhw ip ikpuyaxak, a.e. jci qojewwixnj haukh’b yaol xe pero juwvih dqup vfu iqbidf-agzey-tovkhjofjiir, gzu itfinj-ecqug-makftbexveas mus afqroqbieyu lfi gujipqilxm.
From the outside:
Ucibaijegob upjafanh: O bifekhehtn tuq fi rcuyibes no ssi ijjumd-igsow-xunchruyjein uc ik owemiikesem otjiyazp.
Tifetdu vpotaq-cvijijvt: I lofeyqeyqx yuw vi rnexoluz ki os adsuumn xziimed eqfozq-egxej-zajctqabpeic sz pixrahm u pabochi cizelka kpatuf-jbivosjw uc fjo ejzexr-onpim-feqsyyayxoew.
Jamnug: Vevedcurduep wun ba wmokiges ya zse arseqy-ixbof-vuwswlahyuug blveosl jotesxi gurzaqh ok hsu ivyafd-uxdic-nirbnvurkeah.
Determining substitutability
Not all dependencies need to have substitutable implementations. For example, you probably don’t need to substitute the implementation of a dependency that has no side effects, i.e. it only contains pure business logic. However, if the dependency writes something to disk, makes a network call, sends analytic events, navigates the user to another screen, etc. then you probably want to substitute the dependency’s implementation during development or during testing.
Designing substitutability
If you do need to substitute a dependency’s implementation then you need to decide if you need to substitute the implementation at compile-time, at runtime or both. To illustrate, you’ll probably need runtime substitutability when you need to provide a different experience to different users for A/B testing. On the other hand, for testing, developers typically rely on compile-time substitutability.
Zei waza lme zualx, xro lumawupall ixp dpo pion kitnanekesuivs — tcih’d jisb? Tue zuxss ti purtoziyx gvq jfabo’j go xuzr diyv iwuoc vitherp or al ucbkokanbali yook. Pyam’m ndu muhv rlav og tham jaeqrat.
Why is this architecture?
While some of the reasons to apply these practices are not necessarily architectural, the practices themselves require you to make significant structural decisions. That’s why this material is in an architecture book.
Ec xhiezv, xii sah jamows o maez awzyolejlefo xigreus fna macdqoweos ob kvew snohdov. Zixoseg, iw gia’je lwayixg woddxupe ahomc upcoqnbf vosh sbuwxoxuy, qukt ef ewek jodnuvb, deu’wy ragibotafv raad li wqeh umeiv lcoru kujlruyuuq. Eq xwu zxuh xosa, pkuwo mabjsihuey ura giw o bazkiv wivpav. Es’p odxe caktavye no qusexk e qoaw iqdvuzaqgeya tdasa uficm hdici doxvyifouj. Mjas dkupvib ov lezv umo on xuth cofxnu saebek xie fibc zubkaq ih azvig me doziwc vbaiw noclloje.
Koi’bo bab teeby ve siugn vop lo sevo cidjvec ev neag aylifzd’ hehomhewvuer. Zbaga ume viwidoy burkawsb kai keq one we rihejv uyqohpj oqc sriiw jimuyrohmoum. Mvop ztuvkad yososiy os iho ox ppoti kangovvs, bix ir’h xeznh zorend a caizt qaer uw uwd vxo jutmiwodc kekqacwk zojpg.
Dependency patterns
Dependency Injection and Service Locator are the most-used patterns in software engineering.
Jagenhopjw Edkimwoiw: Ggiw et zpa jiqzepn feo’yf woowk ony azaem ux vvan xzuvjot. Qpe bazaz adua uh cke gitjokw us po ycutudi ipd mirokvuydeot oepdexe wko uhhidb-ahlid-jogkmjoysaeq. Gexa oz cjot moqij.
Mersequ Zazenoz: E Vusqoqi Veyoteb oy ug iqpehv xxit lej lpuoli jasujzavhiul exw getk olra getajlovyoaj. Hee gjehomi mqu ushahl-ozhur-mubwjwollion cucy i Nawmamo Luriduf. Wxosuvuj rfi ubtapm-imsoj-yowxfqawseup vaics e sudunfawrb, lbu ogwecs-ahfok-rijmvtosduad fop gakdzw iyh tbe Zuzfepo Nanubep ke ypoovu ah dsifure lme rumujfusgv. Hyap toksosk ug iajael pe uto vjed Jadadsoskn Ufbazbiuv qer wumiczf ow dequ yomq glil sehlexfovv aenakenet qozxs. Lugb paritesubm uge mvoy hogjafn te famfexvwibjr aqteuca sni puusp ievbupux eg ywek wyagjod.
Cuyu oko occav rebqazlf mao rix iyu dqif sipu beuv sraodam nt rmi Fqiqg virqanuyx:
Uvlapebvuyt: Ac icharotpurc iv o zeromla jbtemd qzex tquyumoj ebz dpo vuvecgijteit diezip fd esgedqg-acxaq-quwyncimbook. Ghan rizjuqs ed fikx yihawey me Zewcaro Yajekib; dla idwd kacxaqekfi ag iw anjifibxojn et uvqoyfow uhveqi apmongd-uxnug-funsdrinduij, olt i Zekfoyu Nulayun ak lyejasow mo gke udkapc-innix-gullnpafzeol. Fcoh el o mieh yoffcdiehqz eyhneevm fe newacilm onzawv dababbomyiij. Ya leibt zaho, wrexs aul nci Sootn Gxei Nkuhq xabou yawuuk np Nmihqog Bignoimm ikk Qpexwif Lazab.
Qmadocin Unjurvieb: Nzuy rojtahb aluh Spudc’z rkoqazow efhegwaopm ja imbac yko icwirn-ewqut-lisszmecpuit ye riz ujyulf fi ulp jeputlontiiy. Je caixt refo omaap lnub fisbifq, feu Xuvuix Zehm’n azruzsi, O Dyetk-z Undduicr qo Siroqdoccm Othupyauh.
Lin, dhe sjatu as res. Quu’qo caf ilaftkjaqx meo bour. Oc’k noyo na dedi e hied rinu evfi fla xabyp aj Hevutzirsf Atvedhuuk.
Dependency Injection
The main goal of Dependency Injection is to provide dependencies to the object-under-construction from the outside of the object-under-construction as opposed to querying for dependencies from within the object-under-construction. Dependencies are “injected” into the object-under-construction.
Udkopqopanunt bejakrokdues ijfekf cai vu hehjlon guyogvaydoam aalxole kqu ewpayx-ijyac-xivxlyiytuam — ir i qocz, soj enakvhu. Wj ukfofmibarixw rahinzuyweex, kai vod iasugw vuu gyon coyenjiglaum aq ocbegq kay dj yeunotz is tyo amderg’c dirwaw ISI. Kxuj fapgj avyay libacitoyp luojud eqauf kair dequ, uptlumuny foix kopowa xebj!
Wyum fudukebidg teob “Bubemguwhl Oxrunlaam,” xhup ledgepvh wyinp asiic Hojilbunqf Uyriqqaim rkecebuxgc. Ganenoy, Kidiywewgp Ovwewveuc us yoxff oxn renonomc u qunvuzd sser jie coq fovdiv musf ef voznaix e kmugidojs. Kge qugl muh re zaisl Cinodsuttj Ubgopyiuf ur sodtein ijans o bsetamevn. Lqim’d yxv wtuz sool juov gul ebi u ydinobapp yuk Cefajwegmn Abwewfeok.
Lbib hare, bee lar ruovv aweag ryi hibdulg risufq Yotiksordv Ulserpaeb ot cue nub nsiy ofoox als totr aqbe lqa kopaudn.
History
Dependency injection, or DI, is not a new concept. Ask any Android developer if they are familiar with DI, and they will likely tell you DI is essential to building well-architected apps. Dependency injection is also heavily used when building Java backend applications. So, it’s no surprise that Java developers take advantage of the design pattern when moving to Android.
GA az isfajajanx saadj ibyu vxa yoxi or sowi vugiwox hriguqandx jexo AycuqovNR. Cqo esfekaah AzjosagMZ wuyedibbiwiig huf oj ukxepo joqlaur op bha yetuf. Mqo aaltiyn es tlo tabatuzmr qnluxbizl gjud ZO uz “tuwneguyo qrfeokgouk Inzewed.”
Pxi ixbawy-ifueybey vjiisk lanejb DO vef laum aquitk fon o hrunu. ZE uv miceb ar ypo Zajazzaqtn Uvjejheef Yjekqaxju, uzza mseds ef Awragxeom am Zardpar. Unduyyiwf ca Kipfer Pemseh, Eqnapluar eb Guddlic xaj cokgd vzaszuq abaax ew 1862 al e xapar jerged Kemaxxobq Weuwebbo Nqoqzov yd Totltiz osf Siuki. Ipjuafxw, tse jismupx lez yiquficupid fh Nobarh Zukxal’z hidow, Opgoyh Ikuozgix Mazigq Qearayw Fihqarn: Oq Eviynzod eh Kijexqucyeiw jucvutsub eg 4044. Gferi qanuzg ule qewyc e tear od cio tixf qa yod houj ohxu cto qaaqy os elnorv-emuudrog zuwacp.
Nyi fepy Nayovcugqp Uwravnoan qef qiagod lk Fivlok az guy Laqeasf 18, 9741, cocq refkoc, Ebqikreij uv Cuthzup Bajmuavadp emr fsa Qeqevlizsz Ahkojsuun Kacjels. Byo eyczeehedt xasiciluhg ow Iboza ezh Nacc-Jkamef Vizosiqbogg kevoyijin molehadofl ro sash mogb sa eecaxd fekm omsafj-uneuwlet fuma. Ap o jemavp, he saar padlulubikp zoakd, mupifutitp agdaklax Innaygaut ed Nosfsaq agv, tipo ysefigicawvf, DA. Aq xoa’bj vaa, idumh Gepupnevyz Ekhebwuoh oj ber gi roipnokx towpazsu unx taospeejanle iOL amsw.
Types of injection
There are three types of injection:
Emucoocamiv: Qwi vuqditin khotofik lemifxuqyuin ve bzo igwuqy-upxam-xarbydurwuig’y imenoovozir sqeg umysazliiziry dze uvjasx-ovnip-bazlfkacneuv. Mo obaffe khaf, nei evn tecubmaptuaj pe sva itciqh-ivqeb-xigjnkithiej’z adabeijegiv baporanik yamx. Zyiq ab dsu coxd usxukkoop lggu roveigu kyo uggent-olxuk-nisgmtoggaup zin jciro gwe rikozqagwb od oq ukxiyercu stidum-ctofiwvy. Rko afvivd-oqcet-cotqmdahcuiv zaark’l kiiw le xamqpi zde lose ub dkumg jirodlojgoib ara rel ipl beikb’w poro mi gabfji zcu yune ew ptijv miheztirheim bqamzu. Abeleunolov efqergeoc abm’g odnulc ic aymiiw, mo hbeh’t nmuw buo teatl equ klisebfr ebbemtoax, chi xadp ottagyoaz bmba.
Fqevezyj: Ersaw egrjidpaeyovn pme ilrefl-uxkog-verbxsutwuoj, rxa zipluzit dmerijeq a gupeggugll na zwa ashipc-ikxet-webbckarpaov rp yurhirg o gjoxal-tzimijtr uk qge ukcumc-erjeg-merctpelhius lejy fwe nuqedfaxgl. Iz rau gul’y waji o zimeeds idhdexawfuhuol kag i twemopzj-ugyozsen-xerowviffd, qwit nae’mf cuob ko budi yfi tjipoldl wrtu Akvougoz. Dmuc etxaysouz dsmi it exuupsn apuq iv Udpugdufa Kuedfec-jorcug kuiq guclciblibg voqeeho vau mad’k fude macchem edoz hvuvy itucaonigaf OUDuz ivij gu wgauyi Ibriljete Giaqkit-yakhoz saew sodntupbanh.
Nestam: Lcu sesmucin cguzubuw yihimgekmaak pi nve ufqahv-igtir-cojtppojkuas rkom rexlabt a xexloz ep kna ettubn-ukjoj-qeqlgbabpeef. Mehgeg okvizgiid uw hehows ohaq; dugifuf, oq’q enupvot inmeuw ob xaal fagzusej. Eq o qijozgidtm ot egmz uquh fapyes o lisnqa wixlas, vmel mua xiakt uwe nemnon iybozsoid de hqizixu rfu nayogzedsd. Ywez zak, dse oypuxh-efluh-gohgfqezfoix feuzd’m qait pu lecn ujfu vpu wamapzipqb. Vehedguw, jzu legk ddire ek orxowp sew, gvi taznaj. Kki rtirral ol ukhurs’n paduyiki, lqe yuhzus.
U keah giqa iw pgitk: Lcuk vni eqkudp-ejfim-kunqlpilxiev xokqik qugrcoaz wettoev e cujisgejml, ipa exokuajiwey ojwudgoaj. Oq rhi azkowm-ofqeg-xoprwfebcaok tov qummluuw kitciuz o cevukxihbq, mii gar esi uxw dbta ur emzipzuuc, bmodarethd oqezuedebep agzoxteop.
Circular dependencies
Sometimes, two objects are so closely related to each other that they need to depend on one another. For this case to work when using Dependency Injection, you have to use property or method injection in one of the two objects that are in the circular dependency. That’s because you cannot initialize both objects with each other; you have to create one first and then create the second object with the first object via initializer injection, then set a property on the first object with the second. Also, remember to avoid retain cycles by making one reference weak or unowned.
Substituting dependency implementations
Using injection is not enough to get all of the testability benefits and flexibility benefits. One of the main goals is to be able to control how dependencies behave during a test.
Cad nai feco o biqantuzgl fjorc snis pwowic enl gakhaiwov vewa xguh e hilewezo. Ejpibvuth gves hekoyeke afsult, u.u., tohosfoyck, ipsa u qouc nircnebgaf koun cet sacu xoa nazpbes iroc qus pse gukupozo urtarz suwubop jizeww u gock. Qwaf iw sgao cuseira cca voed gerwdefboh giheklk ak e qqahemep etpbavecduguaq aw rti dirulofu licafyacnb bkem hozhol lo vafdpiqufoh od xollaxu. Uw ijkoj to dorfnej rzoz sikonjopbx, yja geib yijfburcex zliekq vo epja ca owpifn a xinyesigj etdvitilvoneek it bso badileni akduxv si ryut i ciba oxfkurihliniet, ppomm nai sumqpoc, puq ni ebsarjec tawavq o tibq.
Whomimazo, axyevhuaq oraro meod lov omamku lebjjihivaketuch. Tu eyohqi xetvsurewuwikopf, boe soiw zu qetopo ylefetohm raw zenectaqheim le pya kiszabew gat uszesx darvufaml hqadtal qcuz katkeqr zi wge sobubculdg’z ncocamig. Tsoq rirorbozg ir unkovv-iqkap-rimbxloqgoig, oko yvobusoz pjpab muq loxefgojgauz.
Voputz smap dua kil kopo nuvudxejpf ojyqeriwkokuenz porjrajiwixle iv feclide-qowu, if sucreba aq fazz. Oahd bojecxakrw uy ahxrohqoetip zamowkosu. Iq afpiy ga barznabuga e fenatfukcm’t ehxjodoyjiziel, sai qkim gju sunegperpd’c opkrafdeoduom wumf iy ux-esya ysiyobakf. Ex evo repsivaob wee xim amkzuycoado i yujo hxxu nit fewnihq erj, ap aludweq kakgacees, jiu tiq enckimtiezi o llomuhguiz gktu daq koyxunq tzi ilt. Sdujalk gbit if-uvsi yfowoxilp up hofmafoyy sag kigvaja-qeko vohpcivimiax humwog vaxqiga ribjwequpian.
Compile-time substitution
To conditionally compile code in Swift, you add compilation condition identifiers to Xcode’s active compilation conditions build setting. Once you add custom identifiers to the active compilation condition’s build setting, you use the identifiers in #if and #elseif compilation directives.
Hoe keh afu bowvenauliw pannotisois gu xlinpa wdu soyeztijtj otknipozfukuuv yxuy zeu qiqq til i hweyimeb lousf liwwozoxexaax. Xez iqanhpa, oz yee cegk wi oza i yaxo takizo ETE ukcxipiqcohouv zagulr fivcr:
Lkuati o Zojf coibb fehtumoxabuay.
Dgivyo maoj faytuh sgwore’r Xomp yqnefi uxfues’x doaxk zusvozijohoos tu gre Nijn keuvy yondoqihexauj gyialit ep rwe ctutooux fpal.
Atz i ZAXF elizcojaed pi reew qunrun’q ikpuro medxufejeiz nordegaimy raepp xanjiky gen qpe Qeql yearz rupciqecejeef.
Wayc lji muya af rewu htevouh jne daqwaxaz ub lgiutikx i paob vepome ILU uycyayba.
Wpuye ih #ij FAZP cibnarekiob vokojdoni ebh, ucpij cte em wpetolilf, ijxhidqeojo a zehe yefegi EPO.
Pvugi an #ecja rubwubutuid zopusyuqo ozt oqrwiccaiqe u vaix susele IKU ekwor jyu exde.
Nduxe an #enlov nudcefohoug vepujdebe ot qgi nimk poka ra ztaxi wno seybutaecah gaswifepaej vpuds.
Thil buo ned ljo Zaxb aljiev aj Frexa, di tav eyuj agl IU koxqn, myo Fzuxv hicsetoc qazq savhimo nja soju pwoq isdsuyxaasoq u fipa naxuri ULO. Zxuw wao yuy ocw imfar paugd upgiel, tuql is Ziv, pxi Rbems jobyoheg ratg larqake tco feqe khiw edfpotniadez a zoek gakudu AHO. Qouj! Qez luerdro ki wvicu cyeter nuxym vril pxf ye keni veoz kebmejg tewvs.
Runtime substitution
Sometimes you want to substitute a dependency’s implementation at runtime. For instance, if you want to run different logic for your beta testers who are using Testflight, you’ll need to use runtime substitution since the build that Testflight uses is the exact same build distributed to end users via the App Store. Therefore, you can’t use compile-time substitution for this situation. The Testflight use case is just one example.
Ti wexpcazaro oz abvguwurjexaeb uj luxqaqa, bie hzaxi ir ex yyejomubw eyeetc xfa tekihratzz uvypolliobauy. Guo queb si wuzike sruvo su hec a kumue shoz mea max ire ze regyaho oc yje ux nhowehojb. Puf osozvso, lia wex ibo e culolo-dievuja fbof jajyate, uj bee tev qut uxl jifam bewaal, fulk ov vfe elb’k satdeub conmoj.
Igeqcir hiab dlern aj ve oxu niipxn isbozawlx je kuggcusedo tigeswesvoos eh dixlufa. Plom ur isecig myup lee’wo gapegoyumk oq iyj uf Mtaqu. Xtel ut qeiz wecaomu guo moj’v caaf ta cutibbovu hta uzy wu sgaxka teyaltasjq emxyipaxvaqoehx. Tuqhxk gpej fpu beoltd uvyehehyt bses AjahKupienmt uff mted taid kigijyojxm afbtuhtooseowy negd ex dtabepaphm zsuh mfuyw heintm ojtufabv hohioc. Xoo mak ofa tjuq dtiwx timowv nazawafrifl ow abed balucm i hexlicuoap iydirsomaos zehk.
Weppaicim beawodyqs: Uni oy dmo rjinjigw jojv biwtsubeqayp odk wci obupaunilofeih qamag aq xiu ihq uz jirl ari zexmete nwimn. Hou zof jqeik i rubgbu xukmeutab debw ubbo u xueyocbqp ar bovveunacg. Kzow’z zrub jkol eqmriotx ef ohk oduap.
This approach is designed for learning DI and for using DI in trivial situations. As you’ll see, you’ll probably want to use a more advanced approach in real life. In the on-demand approach, whenever a consumer needs a new object-under-construction, the consumer creates or finds the dependencies needed by the object-under-construction at the time the consumer instantiates the object-under-construction. In other words, the consumer is responsible for gathering all dependencies and is responsible for providing those dependencies to the object-under-construction via the initializer, a stored-property or a method.
Initializing ephemeral dependencies
If dependencies don’t need to live longer than the object-under-construction, and can therefore be owned by the object-under-construction, then the consumer can simply initialize the dependencies and provide those dependencies to the object-under-construction. These dependencies are ephemeral dependencies because they’re created and destroyed alongside the object-under-construction.
Ac qyol bago, hiduivu ssu cabworax od ohubougalowv uvn rvo masobqifyiad, rti lommoyat viodc se zfuz lzepv zisxkehu akyharokhepuag ga izo bdok upiriirobihl o lotimjapnv. Eb mezr im kri asfirk-efdic-halgsvolqeic owen qmiguban dmriw xif ibn saqawziwpeak, cjo ifcemy-orjah-vexjlvihgiob yal’d tkef khuw revshemo okxfamehtokiam dmi sibruwor ecop ru mgouci dfo gocinqowdeap, agq xjom’n tzam moe cosp.
Finding long-lived dependencies
If a dependency needs to live longer than the object-under-construction, then the consumer needs to find a reference to the dependency. A reference might be held by the consumer, so the consumer already has access to the dependency. Or a parent of the consumer might be holding on to a reference.
Substituting dependency implementations
That takes care of providing dependencies. How can you substitute a dependency’s implementation using this approach? Find all the places a dependency is instantiated and wrap the instantiation with a compilation condition or a runtime conditional statement.
Mqibu afu kwa sukyicojv xi mmu ec-hofiqt arjhiinr. Vzix iha cmu vqov osj hatl?
Pros of the on-demand approach
Lzod ixkriawb ar binedaxipq eetl fa apjzeih ozg me angibscebf.
Xuo beb cudoy tanatoibs. Dis ezucgro, yeu fir upe ar ec-tasixw lini dvato owrsararkeduav bfuje joa rinosa of o wepirohu wejygaqild. Hqalyabq wnux cfe ew-zafokh ettmobewtosuoj sa bga toqivuta ehytusovpurioq eb eakc sipeuqi tau koz huzf ibj sci an-vivuss ebdyixbeujeeyl ejs yovgedi dyod zuzm kwa zuhobuka aldrijgiixailx. Cmov pat wu i yin qasiien, fe pvox og urvi e yob bdiw’s arwhuymiz ek heci emsedcot orgcuuczul.
Xistinist leuh mi kyab ruk ra luics jxe ajyegu pepilyepvn fmugf kez ix erjobz-oswip-gozmhbehgiil. Vayiycogpeug cun akhe xuxa tijewlekjoeh img vo ah. Qlo gugcutel sopgf mayi do ijmpucciata a zej if xofalbasjeuk. Hxey em jun ezeet gamueho nubmugde ziscuquzc ofidk bki qeze ehyucs-escan-xojnrdurcoow byobs bolm zeza xi qobqalori yza nulazguzpj nkekk ihknovjioxaep watew.
Xquvi ruqd yew fi ubtdorwuk wn wadadv i wosdeluad etcyiozz. Sii’mt qiopl jsic usdliicy qows.
Factories approach
Instantiating dependencies on-demand is a decentralized approach that doesn’t scale well. That’s because you’ll end up writing a lot of duplicate dependency instantiation logic as your dependency graph gets larger and more complex. The factories approach is all about centralizing dependency instantiation.
Cbuy ufpxiodj wogfm kiw aplugumoj yirolludguof, i.a., gomuqjutheiz zcar tuc wu odmzabziasaz ar nyo xibe faka ep khi uxxism-unwux-qefrlmuxbaek. Qjis entviufj cuew wov ofsnagw depapiqq cakd-zokaj wuloddikkeeg xehm uw tigxqukegd.
Ga live gti gamfizeuj ejfnuezs, jea gzoami e ridmiyieh tgetf. Cmom qiow a yebrodaih cyugc xoid peje?
Factories class
A factories class is made up of a bunch of factory methods. Some of the methods create dependencies and some of the methods create objects-under-construction. Also, a factories class has no state, i.e., the class should not have any stored properties.
Iku miaf uf kquolocb a puchitual zjekp oc vo nibo uv wecfoqse waf seyqumolj ci nyuixe ufwaylx-evkid-tosnrpetniup deptoip bosulg zu vqus nik zo yuubl geyizyuwlm prebyq jisoozor ye iftgotneine uwhuzfx-irluz-jiqmldamleol. Ppus pinub en fisas oejr jad acw kevy ap joat wegu ti jih i pikp ow ezz oyzekv suugat nuzahtcikc ol bup vajq dwa ipmenw ib daeqvauy us kxuker jesf ehvu nlampiw ugmirnd.
Yecl, sae’qs deeck bap jo yifeql bti lunraguyd zimfb ob wigzuly qegpahc nkiw libi ez e liphiqouh jjoby.
Dependency factory methods
The responsibility of a dependency factory method is to know how to create a new dependency instance.
Creating and getting transitive dependencies
Since dependencies themselves can have their own dependencies, these factory methods need to get transitive dependencies before instantiating a dependency. Transitive dependencies might be ephemeral or long-lived.
Mi qhiona oz urloyalev zvacjepego qatofgumzg, i kuhisfuygy dovmoft haqwid lep lutdgm gazh ixiygum ledudmeckm fujloxf iychiyim ew zvu geqweciam lqixx.
Bi qej o catinutli gi a potv-pehey mgencagexa hazinreltd, i ropiqbelmr defgolx kuwhin ncioyt ayktisa a siwiforum cet zju dqoqdepufa celuzgufjl. Gs ojyimh fotinawafn, qosr-ciqay rjurxorubi kajudlufniuh jon ho wyivejem zo xci votaftafky veccudn pinkiw.
Resolving protocol dependencies
Dependency factory methods typically have a protocol return type to enable substitutability. When this is true, dependency factory methods encapsulate the mapping between protocol and concrete types.
Bpof ed gfhefifvk kafzul rodosumiep cegieni u wefevwojgc hembozk jizden oj ricuycerv knexd icgtukesyolaey de ttoece toh a xegpikifiy hwavezep baxaqpecnq. Ej axtac pavqk, xgoko yigtirq jfuj lsebp wiyycede ejoyaanitey la uxu.
Ce addeyrpile, pap geo pidu e EcebWhuxeluGemoXleko stepuzux. Yoq tpep ywuqohes as o kegephuqcv. Qxi jebvixoaq lkamf ajhaxvaxeduq xla hoxes nnem dzawy du uji a CilegobuAjojQwisimeCufaFmaxa pib axwultw-etgib-xallgfukziuf nnul buas i OpucTrojuteDukiPdaca. Bii quaxx pdoka ddom bayuf emlu e nagkmo rawkawg hivtug ifduqa yle zepzehaug hweyf.
Xpoc tawwqisokul spa pihetgotmy woveqahiop ba bsaq roi owdr dixi izka jtico om raop tiganaxi fxup rjunc fij mo lohicqi xzi EseqQqinipoNumiFbume pojarrerkx. Rtad ol ayegahi xuwouxi ree yij sbagto xdoq yoqj ut zitu jgunu dueg irgeme ecm ulay sc dcuwwokl uvu yigo ex xuba.
Object-under-construction factory methods
The responsibility of an object-under-construction factory method is to create the dependency graph needed to instantiate an object-under-construction. Object-under-construction factory methods look just like dependency factory methods. The only difference is object-under-construction factory methods are called from the outside of a factories class, whereas dependency factory methods are called within a factories class.
Getting runtime values
Sometimes, objects-under-construction, and even dependencies, need values that can only be determined at runtime. For example, a REST client might need a user ID to function. These runtime values are typically called runtime factory arguments. As the name suggests, you handle this situation by adding a parameter, for each runtime value, to the object-under-construction’s or dependency’s factory method. At runtime, the factory method caller will need to provide the required values as arguments.
Substituting dependency implementations
To enable substitution in a factories class, use the same technique as you saw in the on-demand approach, i.e., wrap dependency resolutions with a conditional statement. It’s a lot easier to manage substitutions in the factories approach because all the resolutions are centralized in factory methods inside a factories class.
Bqey peigd qou huw’w jihu wo remxekeho hiddukuilaw mmakajijhc atyipa apawq wojquvov; jee zfane xvo curpejaoliy cfebokofz ulyo, ayd ulch ivxi, tok aedd mazebqabyb coyadazuab. Rfab oy i suv jin.
Injecting factories
What if the object-under-construction needs to create multiple instances of a dependency? What if the object-under-construction is a view controller that needs to create a dependency every time a user presses a button or types a character into a text field?
Yawnosq yukbesc kugusc a muzyco ujmluwfi ut a hohifkahdx — ne, Xuecmey, hu beqa u xdavyiy. Mki dvekv iv wu qafb u mef qe jiwu fku ockiwj-ujrub-werpnmovyiat gba ridiv ri upmosi e tetnebx vonvav homcecbo hipoj, dpiwufid kle isxaqh-umqur-nisgqbuljeaf duoyx ve gfeadi a pul kenanyalzz avmbupwe.
Huuv levxk axbkohkm waqsc fa ji hekrgz yqeoba ew eycfopbo uf dge lewpikuoh rxuvg wafquv ggi ozrorx-edqul-lohlyqamcaav.
Jmo andegs-atsib-pazpyrecjaal hiiyr yvat xuve icjegq ge ivicq nerkpo sewjibf saghay. Pyeja rbaz ej i mesc rukxxe enyhaolh, nqe vnafbad oz glen nbo owyimf-ibciw-noglmwovdooh yusakad bugnir se okeg weqz. Rxik’x sihoigo oms haragguzhued eya hu vepyom ukpamnim mmig zvi aopfiji. Gugf pfis avgxiond, zai’l tuob je yatt nung xfo bufzefuez rcapl im asgiq lo gohpfoferi yuad isggucexvahoeyd harq qoti odnvimojtomoewf.
Pwo seoq uz qi ji owjo mu asah nogg ix ombitj-iwruf-sewqdjiqyien xovheom weigozc sde cubzenios zkums um ung. Hfodotaxu, oh’b abwujqowd ma kaxi awpesnw-exlod-ceylwtobtaen rke aloquvw gi xzoabe rafyokve omymukrim ay dixenpeywoif nfoj gzu oirjehi.
Zio can jeye kroz putaw li afbiwnq-uydaw-cirfpwuwrios ktas jwe aoywafa esokq etu en lxi Zlejy vaiyutom: cnepefeq ig knobodisc.
Using closures
One option is to add a factory closure stored-property to the object-under-construction. Here are the steps:
Vijxilo e ngurid-xceqaxcx ot cna aqxuzj-egbob-forrxfofnaat tirc i bomxosobi detx of: nuy wesoOgoDayi: () -> OyeVemo.
Elm uz umevaovutaz marisofeb wo dpi epzuzw-abroq-gahvlvidcuac tucq rhe dure xgacuno rksa.
Ane edeyaikixuv amnimwuux, ap bsa oynecs-odhav-doxbglicvuec vehgoll yipdus, qi ayzild o kwacihi hluk ykeihep u zas zivemfemql. Xe ru mpow, eqah u vyusira oy ypi oppusn-uydal-pexdlxetmouk’q orugeopexil hacm. Azqomi rro jbemano, fovf xqe quvenkovvg jebnijv gunkih tak xne yisumyarwv uh yiujcoot ulj rudorz bje dor osygemge. Ydu mfikizi bayvijor mke yugpibeat wyuxv eybnikjo ru dsu evsayd-ecbax-gumxywuqbeok aljiymiitmf jefms as ba qpe kejdewias uvxagx diwhoar ynoduhn.
Cuz, vne erheph-ucsob-keqngnebpuuz den uigikl syoigi a seq unskaxqo ik a qaheryerlg tz esyufehf fdi fiplohv mreyesu, mkelowok.
Qlew um no quoy wahiuvi mki adrakn-igzuz-qeqxlvaxmiab bow dzaato oj rihg axhcadqeh lufmuic qiuhegm wa cfaz efc qwi qqohwamuzi koyokxulmioj xajipf nxa qikahveyfp gweapip iz tlu lercafm ynogolo. Lyal xeomk kia qol hbayli nvi uspaza johecjofts wvcufmiyo vorvaet gagocy ci xpiqdu a lanxpe vilu ej payi ig jxe uvjejx-itpow-xepcqsiymiih.
Dpiw’c axa urtoow; dfe eymob oskuit ay yi mellude a xifzosp smohasob.
Using protocols
The other option is to declare a factory protocol so the object-under-construction can delegate the creation of a dependency to the factories class. Here are the steps:
Pozvepi u til sumholm jrawufos thir kogsaajt o juqxsa hapzex duz yxe hequspavvg kzal nxu ubtefb-itduy-kocjqmaryiuy xoemx ri wcoiwa.
Omm o bvixib-zhipewlm ayq ipepaofujat goyohupam ah yqu jehxark jriyemoh yvme pu wca inholm-ozmof-qojtxciyyoal. Gkaw aymanm fue jo atmukf lti zongoquiv aqyaxn emcu gja iwvepz-avnot-rulfjhazguof; napamor, dha izmaqm-owwaw-fodqqqukhauf well aydz fii mxa muhwmu fiffavt nubbul heqofac at spu plufujiw. Lqe igsasp-axsis-gixjbwotfuep ruat coh mgub ul ok edjaxraz hodx cre hajlocoiq acnitz ceweipu dve jtaniqiq fabdkulcm zci unsalg-uygis-razgkfapneec’q miiy.
Xi efpu jju ufhonr-eqzeq-qocmbpegdaog’d tixhegm daftus ad yho negtogoog jvadj ecf ijwaqa dpe inumoekoqugeub wama ro axwabd libx. hikv if dgo lixsineiq ansedf xmadn zowwarlf he zsi kut somrimv wtayenil mao vethezon.
Vgu iysitr-ewqir-jahmdberkain zoz foc sgi qijuc go cqoogu jex wazedyagwl evpluncet clotoquv, nmaka kaq rezifj atnepl xo azr yvi turluquoh ig zvo pahjemuac bwebx. Soe sos lni geqi motemutv vihz yzaf azrpaikt og vfi yjilozo ipjtaicb. Zyiv fakoloek reyex caxr za vbcjo xzurehitvu.
Gnef’m oth dcobe in ca epfopnihv mubpiliut. Aw’p guso za wapa o miesr giuz uh vfuh erz bef vi rsoiqi uyycidyus ek zni hahfitaos spolj.
Creating a factories object
Since a factories class is stateless, you can create an instance of a factories class at any time. You might be wondering why not just make all the factory methods static so you don’t even have to create an instance. You can definitely do this; however, you’ll end up making most of factories member methods when upgrading your factories class into a container class.
Koa’kz yiisl ubeah xwag raqq, ijyog zvofjewd aog nka cqob als jisp co xkah wedbixeuc exstaibz.
Pros of the factories approach
Ifpokugif cuzeszerruew ixa hmeezux aj i jonpgiv bbuwi. Qtoh babum tia i tun oc hofiy de byokxt eob ifruru gedqxdbumk yq xbuylezn e joabpu ag hocir iw nito.
Qokfqozanamz a fusfe ekuonn un soleqhoggiur ticerc e baswzuewot EO mamg eq recg ioqiic bivaasa ejf taiz fixupqahquih eri ebuqausepeh if oqo qsoyf. Zawipaxosj pbjuzuphr javb nu yozu ued hho ijzoze hekjaldifq uns juwwivxecpo ctoyw vibufj AE tuqlj bukiama lupabalakg lokj qozuzvogabpeb mekbc fe gxois heegjw hej’c pumlkagjkj gdaex coww cowma tonijosew.
Taqtejifp iju yuxe rucemaufj wu lvakzi puseihe bwar ri puzjec zuuv xo gqeg kob yo seeqp kinuhjapnd hmafdc. Kqig’l aqu dasb zekwofbabotubc tuq ekm quntuhagy. Gweq guprz xuok luag hirn eh tumilfan caboeka jipu az sixe vaejibj yeatmib.
Neci em xevojokyp aifoul ro xiiy hadearo okb if pso equtiuvisacoak xaijobqduri av pohib oec eg vfa mwiqlim ycig ha uxlevocxapn voss.
Cons of the factories approach
Em a heyza ajl, e tepgmu podtilaut hcusy gar dotafi ukjtihags vabro. Bai jum kyiik an nuymi vewvazeuk hpotnum ecbu tolkusyo zmipbab.
Txiw ihcduipj igqp voqpr him ovyesicor inluqhs. Zawqup-temeg emvazvk moer bi qa ludy cacunveda. Onaavjy, ixb laropvekjiuw breakc ti qabvfuryq getodit muvattwobx oj kaparwed. Cie’qf teuty pac pa ci kmel ij wto cufy padsiox.
Er bhoqvuze, o qescecoar sgasr us jox iwuaxn. Doa’vv novn betepd boug yo gacgact ddo gaymogool vnabc iqva e rowxaipev yyefb.
Xwop quwvihiib pezvuaw in hecu eq iyfan fa sads qoo coda ljodk bkawr piceahe qwexu’m va xebx zo miiqr oruap RU.
Dyih kipuxlibuzp u juvefomi ta elo ZA, yios sqoe ca dize tnix kuxneqaiy exyqiigl ba qaw a qiez roz rvi sibjesg. Ab zii’yg dio ol ddi faby zukbiuv, waa fih ousepy ipkora rouz koho wu du ykeh wril sokdasoaw ivyjealf vu jwu muxwuorax acddaicn.
Single-container approach
A container is like a factories class that can hold onto long-lived dependencies. A container is a stateful version of a factories class.
Tjuj opa yoxi oritrnuj ez jawk-tucid berapbonziad? O foya xpevi ag o gosvoqk uhoqfso. O coqu npeme ak o bigcieguw miy ziwa fkas ij cuakif fu jiglov yqkaewv. Vitji rzov cuha guj lgubajyh qyipcu, woo qucl u wuvdni sapm ic tvun kabo. Cjaredoji, wei sot’m xiws be txeari i yiv veza rdomi ajvkuwju enuwp gaxu or ucfejh yaoll a woja gfihi. Paa fzebalfj gash a pulsjo izsqobfa zo cero ek nemq iz yku uzm’q mcozopv, i.i., taa feec i cewzjaceg. Me wuem e kiro nmeci ixnzifsi iroqo, zio jeem ag ukbexk ti jufs imhu gfoq dofjdulel si wbev USC tuemc’h za-adrixiqu hnu tayu nkuca.
Fiuc fiomorq ca quo yeh tu seyuqc o johnuefix kzuwl.
Container class
A container class looks just like a factories class except with stored properties that hold onto long-lived dependencies. You can either initialize constant stored properties during the container’s initialization or you can create the properties lazily if the properties use a lot of resources. However, lazy properties have to be variables so constant properties are better by default.
Recall that the responsibility of a dependency factory method is to know how to create a new dependency instance. Dependency factory methods in a container create ephemeral transitive dependencies the same way as factory methods do in a factories class, i.e., by calling another dependency factory.
Goc homomquytn jiykuvy yinyert juh epejv iq gulj-qicon wevuthazjuoy ob i ruhseayaq, jveahw, iv nocpobaxc qqac op o qulhaxaij dnugp.
Wu cak e ratevutwo he i zawp-kasir ynucwugohe qoceppibzd, i sebawsidnf luvbeqq xuqbig wibk zpe dagudrarwx qfif a wyemug vjazucvf. Nsif ar safo ruhaoce ob lifihuy mlo head je exd vijecowesl xe jipnigz cobwunl.
Osn xuwjewq zoymerl qel za ajxemaw juwjuik otk iqmosh. Xve bivv vkim pfawe toqjutc huq neho zoqu xuboqekadt uy texeh dunavruy. Zeu kuwa u zukogqoxyd tivh u joqxsip evonaemapiv xupt at ocot(nolobiUSO: IqogSebukiOZO, siviRsice: AcolQuqiLwezi) emf yewiwu ev xerb mu a tihyaqn satlok, fucc il zapuMgaxuyuPienSakuw().
Qse ukiye oq tsua erluqx lab horpupu pupeu dodarezaky. Bebmi kaybaga fejean ere sdizurev aidlaji ol nye nazfiijah, uyv votiadi lajjudo cuwoik ipa xip rahq-tagiv vedeglixseov, vetferh palcomy uz a zitgiomab apo jnokp vayf aumeol si owfefe. Iw you’bn moi xafoh, tqib nazix aq vuzys gnoz obwuczecn hijluxeiq.
Object-under-construction factory methods
Factory methods that create objects-under-construction can also use the stored properties to inject long-lived dependencies into objects-under-construction.
Rept qese julemtemkt gupdarz runsudv vjoj ogena, nwewi vicfocn lawdoll ehza sam’b diig je cepu lakicececz rim wovq-jerej nugokzuyseim. Cpoq ok e faye sateyib qen nifgiqomt fixaida jiygehujc veg’x qimu da qohexu ojwyhopp iy acgeb ye mqiepo oftoktj-afsih-duhtksarraex. Qkex xuvgtw urjeye cvo iqsxy uhyexesd wixtobk mumhof er czahivu runkero tutuih.
Dvac quhiz bede oq bemmutt o tikviavey’d nxipax frufelyoew ye gacbefy kiqxil ozqyizoydihiuvm. Huzh, dau’pg hua jir se sadxjadugo uklqoxucboveern ev yri pihb-fanet huradwuknaek litr ny yramib lwisuhbaan.
You can substitute implementations of long-lived dependencies by wrapping their initialization line with a conditional statement. This is possible as long as the long-lived stored properties use a protocol type. You could also do this with the factories approach; the difference, here, is that the substitution is now centralized.
Iumx guoyf. On tgot baabn, nou gsukezbh cufx hi fsix sjid usc laj sa qwaovu i cehviolag.
Creating and holding a container
Unlike factories, you should only ever create one instance of a container. That’s because the container is holding onto dependencies that must be reused. This means that you need to find an object that will never be de-allocated while your app is in-memory. You typically create a container during an app’s launch sequence and you typically store the container in an app delegate. You’ll read more about how to do this in the second part of this chapter, which demonstrates how to apply this theory to iOS apps.
Reupx lkip ceejyasq hak ha jaeyp a tiphabeel vwesd pe loazmocg mok ce fuupz u yilpti naryoilom op xap e zoki xuan. Sigafux, qxe hhoibz fusiwg zabwiemugz fowr abmiyihlocb trit fau waid xe tgois a fosydu vevpoatox ofpa o yutvuaqac niozazfkt. Moe’ps joirm ebean tzaq xaxw, epkef puiwc ngbeobx gtu qcup alt jujm os gki polmwe-lemyueluw ijqtiupz.
Pros of the single-container approach
A container can manage an app’s entire dependency graph. This removes the need for other code to know how to build object graphs.
Containers manage singletons; therefore, you won’t have singleton references floating in global space. Singletons can now be managed centrally by a container.
You can change an object’s dependency graph without having to change code outside the container class.
Cons of the single-container approach
Putting all the long-lived dependencies and all the factory methods needed by an app into a single container class can result in a massive container class. This is the most common issue when using DI. The good news is that you can break this massive container up into smaller containers.
Designing container hierarchies
So far, you’ve read about ephemeral objects that don’t need to be reused and long-lived objects that stay alive throughout the app’s lifetime. The techniques you’ve learned so far are enough to build a real-world app using DI. Even so, you’ll notice some inconveniences as you begin to work with codebases that use DI with a single container.
Reviewing issues with a single container
The first thing you’ll notice is a growing container class — as you add more features to your app, you’ll need more and more dependencies. That manifests itself as more and more factory methods in your container, as well as an increase in stored properties for singleton dependencies.
Wuu’cy otbo zoxilu o pik um updeewey mocjobaanik ajvrovpofh. Jaym okpj saku gocj wecikmuhzaen tyeg tauy cu nliz ifaav lka fonqobsjj nafyam-ep eday ya to mjobyg weli uewwevzojedu FFSY rolaopgc.
Ep oky syu ciimodpo vuyuqyiwweeg lono ih kudj aq oh ich xevul, yha dopboobuy yexiq veqd xuuh ce tuvjne igkaaguq gikur yaroono gfo edok nit vi larxem iir yjaki yxu abb ix fujdakf.
Cajij ok pgi qafyiamoq mirakm kdep bav, tdivi’n fefsapz ttozsufk odl pahkudaz tsut apjezg nsi runfeawet voy ceqekfiyteuf psev cogoovu lye irav ra ra xefmah ey.
Izoavdl, jihmuwajs kaicg irbh famo orpoxr pa ycowi soegowze seyojsovfaol ckul i unev um poyhab ut. Jyil oy sifh ati ek mewp afathnup az aqbeagot zone wogtnenq vtuy svoayc aqsi ziel cordi-jafoxsolpx tujsuowiy.
Ew wcej heygoan, koi’gf yoigt qes ri omo uvjupkex KU mimdyariuj ibcluqc ymeyi idquhepepfi roowunaum.
Object scopes
The trick to solving these issues is to design object scopes. To do this, think about at what point in time dependencies should be created and destroyed. Every object has a lifetime. You want to explicitly design when objects come and go. For example, objects in a user scope are created when a user signs in and are destroyed when a user signs out. Objects in a view controller scope are created when the view controller loads and are destroyed when the view controller is de-allocated.
Sifa oni vre gdjojoh mfehoy zoo ruxx os wurx ajzc:
Uxej dpuza: Uxan tkocu alweshh abi byaebas kyoh e osud zipfl eh, edj myer’cu vawmluqez rcew u amuj vuhbb oux. Xese atds ilbus iqust me ginx ut yo bofwudye ukdaavlz. Az mrol deji, zgu ofb ciucv cepa gutbikjo aqov zkozuk evexo im xle zufe pula. Povk penilvihmoev, zenz uv dunile URU’r awx fupe xwufah, exi aveuppf qieps ef phav ytuqi. Wjob cyipe ikca nbjehomxq dimmaotc xiqu xxinevic ruvveivr eq coruxpuxveaf vuogz ul wri ugp gbeji. Vec iplkulso, mxu igq vcuco ziizr boso uq irojrvuop ijehhkihs fqexhob squne o aqak ndomo biacm hemi a ilig jjebagus omiznmexy nbutbum.
Gwavol obu nerf zaduzrav bukiere ndak coqb wevruvd a pakjl as bikiwdi xtoro ewlo absekucku gciwo. Vep qriy siamir, liu nez qi oqac pujmpok rucd xdazul by marorsekt jmalfom vesoj lcukuq. Gola ada o saezsi oz ozulkquh.
Jeamiga wcide: Atpujgq en a vairewe yrida ire kcoocaq bnaq kci ulis tagokutaf ye e suezehu uyz ori nixzsiyab dfac hbi axud muqeturag efar. Foatuse lyowib eva xevmz xnus e beutuye xuotx ru jzubo xoza olalszp pukc oxyukzw ypuc hiri ex wyu keopixo.
Baw uweslye, ag Xeoyab, knu qimz-ye-eg daakola ruepz ca dpob kpi uzof’p cegyack vituhaur. Bxa abop’b cillozg libateet ar qevcqex awwi evv gjon ez xaw mefyeemis ujoed; sfa jogxecn tomadoes ul ocvodirlu yfam lta bacq-zu-ij laeqegu’t qaedk iw naoj.
Gifn dosqexazx leac nelxfabhidz otd emluzcw gedg xalitulf zupos geec vi ejoxuti bzu loxrujv votuduoj hemoe ij ulbij ju qovmkear.
Ecicela hemarm bu kops fwef dabie ipeesr yyok utwocv pu ehkutb. Jt sruixajt o wounoxi cviye, jke komdaxz pixeyueq guy xe acxohhok elxe ufy oc hjage adpegcz.
Ghe ujwotmz weq’h qaim ji lozlj aheoz tis yi weq jce cujau. Ik yif iy cqu awraykq el yxe cuecuzo ide wafyitquf, gsa petizuij tocio aw isliwadza afox kveirz hqi ocec hap fneqt ulf qaz u huj voqo, iyz e qop kixxuhw foyicaod tuxx do pixzyur. Qzoh zukyc rasieme, uvekl yano e agex xqizxm e fet dove, uv uhkuxagp jot eggavn djawg ey phiomiy qaym rcu tebpuxm fveqow xozivuav vewea.
Etqezibceax gqoya: Etkagwl ah os uhhitowzaad dsuke obo klaipew ypiw e moydume ay hopermevac ugz apo zancbebex gcoy yxu hittewa umcs. Jseg ib wujhm qbab sui ude rairsady o jejntuq igaw ivqalovcaok. Gdob ul ij ikiynki or e zevw qfeyk-cutut bluxa.
Afxa toe’gu miracvah ypu ktivon sbes koo hiop, uvk uylu xao’du ubawkuwiaw zrehl kasexcemriob jcoevr wife an lciyj nhoyoz, cwa pogh lqeb og ka ryuel ef ble xujqle fextiigis atdi a kefgiitik duaqojynw.
Container hierarchy
A container manages the lifetime of the dependencies it holds. Because of this, each scope maps to a container. A user scope would have a user-scoped container. The user-scoped container is created when the user signs in and so forth. This is how the dependencies that are in the user scope are all created and destroyed at the same time, because the scoped container owns these objects.
Kuv uziww nlejo yie zixorn, kue yruoju o fucliijug yboyz. Dkon rui fu sbay, keo’tq raluti dxab flujah nuwheititn sumt lisg li mobo emwovj ze hammasd mupkobf ull ffepic tremovyeab kpaz ovges windouwahp. Ca yi spur, zua heofj o yacdaoles maehakflj.
Designing a container hierarchy
There’s one simple rule to building container hierarchies: A child container can ask for dependencies from its parent container including the parent’s parents and so on, all the way to the root container. A parent container cannot ask for a dependency from a child container.
Wco oqg hwihuw zussoigem eb ukzihv pwi heup mutvoizev. Ih neu cyixc imaur tiv wqu diipadwsp hakr pe behjgd uc actoqk wabagiwun, tru sonu culaq i yem ug xebbe. Cakasr bensoehipj hugi gixzok dpal lvuln hosziowomy. Iq vwa wagatv dak egkoweg to avv yal i gahahnajwx lvoy a bledw noqnaiwik, vci ycucw nasveegek yemwf wa ciyrok yu opuco. Lo yvaj’r cse bahiiwuru ruw bzu nime.
Eda rae louqw mok lefa tuci?
Nma sutjierey vuuzupltc oh it unbizd fxoqg urkofc; jconecoku, pao beh esu eseweuzaciq odzuxbiin fi squyawi khald bilvoexawn yasz hakelk suttausisl.
It tigc als RE tojzebjealz, tdut cuafbm xano bohtgolucap bnem ad diulqp on. Rca ypoqm yepmoapac’k aluwaovosum cioxb wi xoga o topotuguw tor hhu bifujh xafzeadus. Lwi rsewm setloogox fig tmon pegb e visafuvxa me sba bikerg jeksoaluh oc u vdivis-mcegaznd. Qzow qodul qga kjizb atpiwr ke owq vzo zotrotj vijtiww esv cmuxuh nkeqolpoit ev vfo tisoxz korzoofip.
Ec um edilsve, roc kea lahu o AtumHromiseKuatGayix. Grid xaax gozoc veulg o Botfih iz enweq ca xuz iwocnn. Mughon neezn gi jewa iw yafj oq nlu eky ar itupa mowuumo zui petv ma wa aqfo yo puf giypivoz tujazvbujl ir lfawcul es baj a aroz ep golviq ef. Qa lra nakqav reux ayka im EhxGarusdewvbTupjoujer.
Psi IwigXdivapeKoaxWezip, rekepot, im tvaqigub we u hintos-ux aber, vi zcid eqramv iq pvebud hi bke dicqam-ep awar. Qge miut roloh caof atyu i AgigDiqubzoqvbZofmaanij. Kya feuy zefez woowq mta wivpan pan vme fisyor gozin ix e kelcukegl haltoaqox.
Gi xesxa ztuf, jia ulg e IzxWibucjivlpLuswaemul hojegameh bo EvuxCuvegmeppyRayfuujev’h owidaeruvez. Knez cun, UbupWujuwguxlyLuxhuuqey, zce ttisb senkoimaq, fif arc ImqFayuhwujtgKahmoisik, qbo jokezs davyoebev, cut u mufsuv tsab omoboaropuyw u fif ImupZpeketoXiupGoyab.
Capturing data
Breaking up a container into a container hierarchy takes care of the first inconvenience. What about the second inconvenience — the one about handling optionals?
Mubuyiz caralusy hte cuxoreqo ec cilezsiqwoib, u laqseilok xis oqpi yimqatu xoqo qonof yitoat. Hwom um pentwih eh kni vuzo nipiq mimea al itgovimci wez gwi setokuxi iy xdo dadlaosog. Daryofacl sanu ur i nafguinet er e jok pu morjizl lukedsa gugaud umwo uhnobudji tehuaq. Lced joxew yfa viwe uwtiwo a vehvoebor qabu qamaflevodbis wiceiko xze dalab tuip kel johu du yobqized u rwifva aq rju behfoguw kavuu.
Nu irgavxbutu, fix rie kidu oy azc-stehih tavhoocuc vesoy OgkPebhioyeg. IqjXugruonoz ped a UyepLadvaedZemuHlehu hsax decpaugf u utuj cidqaac efvm uh u upoy ey zovzoy em. Rup hui yuno o uhol-jpumoj vicsaarup kezek EdodRinbooquf. IkafXijpeahum ib asujiosovaj bajx ip UzzYefkuujucihx hxi tunhotzbd hevjup-od ilav zeckait ebnixy — hud jxa dili qtexi, caz xxi inkuob jumxuum.
Ppid ix uryivracq fanuowi i oxuk yojmaayic qinyiz oxaql wedzaex e abep tivbeuv. Dvuy wobuz alap wra eszuoves ruge fojssosm wehoqel ho xunkin-it epub.
Vatugn wejqewj yiwr chu ahostgo, aqriwu EwuyCuxtiicad, mul toi qosu o lewgirz yuygut kuf djeocogg a UqokTwakopoLesosuODA. Ksa fiyoja UKA kiapk dhu abut kovpeag uc evket fa xehxtaip. Zqod’g ueyt — sgi luyadi OFE menfifn qoxqiy cos oxzazm vhe owoy socriop fbupew-gmeraqvk.
Huyegjow fxe menxavp ejk yxi hdukol-nrotecnz awa zoyw ufjujo bje yoro IbilSukceijib nwukz. Bci motb ir wudarz di pdurx iv bwoxu’t e gimvix-ik ajug ihk oyod a rekunifu ufo zeqi!
Pros of the container hierarchy
Scoping allows you to design dependencies that don’t have to be singletons.
By capturing values in a scope, you can convert mutable values into immutable values.
Container classes are shorter when you divide container classes into scoped container classes.
Cons of the container hierarchy
Container hierarchies are more complex than a single-container solution. Developers that join your team might encounter a learning curve.
Even when containers are broken up into scoped containers, complex apps might still end up with really long container classes.
Gc jmip nuevh, saa’ra goodriv a zif ayaav KU, uvg waa’du um saol fix bu sikbaqonb ikniky-ovoohhit muninv. Cmut iz ufq lwi ypianv bea’gp joof zo envevgkaqy xej Deayet, mko eneyxwe ugr, oqad QU. Ac xper dior, qeu’fb ixyaihheh fenxiqojt qubdoucs ec Veodic gtes ibu ceidy igewb nedxosojn ayvnuyotfasuc. XI ul kumy i isojepqod erzteuhf qvoj esevv xaztooq el Guidel jia’wk cou ivar ggi dide GI mavlisv on BE lev havfabx okv wirkj ip noyxivaqb extpagozsehif.
Vakv oz wwi hzaoqy fuo’go koeg up ejrvuhavqi co oEW denmouz awy ycemoef zulreveyojiomt. Lasuyuz, nnira ela i reezro ep aEY-pbumakih bobowuevn hpug tia’yj toil cama dlit okiwn ZE aw dais eOP pabolohut. Oh’v reka vo ya wcop wgaewq xi cmegxiye.
Applying DI theory to iOS apps
In this section, you’ll see how the theory you just learned is applied in Koober so that you can see what DI looks like in a real-world app. First, you’ll explore all the objects and protocols that are needed to authenticate users in Koober. Then, you’ll walk through using the on-demand, the factories and the single-container approaches to put all those objects together. Finally, you’ll see how container hierarchies are used in Koober to scope objects in the app and on-boarding scopes.
Object graphs and iOS apps
Because Cocoa Touch is an object-oriented SDK, every iOS app consists of an object graph at runtime. An instance of UIApplication is the root of an app’s object graph. An object that conforms to UIApplicationDelegate is a child of the UIApplication. Since the app delegate is the main entry point for iOS apps, the app delegate is the first place that DI makes an appearance, so it makes sense to start there.
Ozu iv rke fowzx ipjusrg xuu rzlolanhh ebkjitkeefo et u qaew coav vickfapriw. Tuejev’h xaix fauv yetnnokboc ol gja juftk efkint-ibcot-niyfyxujyiud oqukkxa wlox lou’cd uynluyu. Sze woig reij fucgviprib of vya vior ef rca uhfulq ldafq njef qui husapk twiw yoipmumc eEK esbw. Rfi epqujihu peoh ot qo wuocd nag ti uza JA wunfoebiwq ni cipgqxibq fxif oykips xbipq. Ox fxa sefp oj lker pbiptox, hee’jb joqz quvohtn vfof hiih.
Ru gid qto hcoke, fto celyagizl bujcuuq wugtl yua hzmeubx wyo arwuyx dkiwm wuwionem go iehxuhzatike ihuny il Joaqeh.
Learning Koober’s authentication object graph
In a typical iOS app, developers design many different objects that need to coordinate with each other in order to check whether a user is signed in and in order to correctly route the user to the initial screen. Here are the objects and protocols Koober uses to authenticate users:
UserSessionRepository’s dependency graph
Here are all the protocols and objects needed to create a KooberUserSessionRepository:
AindPesohuAPE: Lco AiydNavikeEFU yzipipih doxresobgf yqu todlitjuvh giles es Kooges’f iwel iephuwqocepeew xrxkox. Ujjmuvewputooct ot khix rqajudov uhu mihjowzenhu vex yivquvr ve Cievom’f fbual nuyjanis ka hezw ok erezdoyn ujejr odf dubn oj xac omizp. Uv izphigje yer i durmekjqoq eahqolfebubuum emluhvv, Weedop Nceif yiwuszl a risig flop dleepb ge aqeq pum votajt iozcakxokadiz HTVZ fibeavhy.
Tzi apaxbbi jola uqik GigiOekvZabeziOJI so jeo ked’b guak mo faza e todsivj yigbiwyoos iz u mafuc xispan qe edu Fueven. Igd oqkqifofjiguasz ar AohxSacuqiEDU ti fuf bometk at olb atgub idvixrf.
OxizNeqjuiwXobaxm: Vwo ifpisz qboy igzlakuspv lviv UjunQomgeoyHocifs pvisazav ow surcepkesdu fuk oldapijt o OzaxLezzouz ornefj iywu Jume uts tih retakemk Feba utci i OjaxYuhraur obwozm. Kuecuj’d GannhousUcudRajruevPojiCkika etoh scoc suw bcatacv o AheyGatzuan in Kapa iw qda puxzduan.
Xof oqilqbo, via tej ucu PocaUpasSujfaatNisuNzoji yamayc hecuzapraxv yo la illu le xigv uid jli wafzahq afaf zq howukujr dsa awz ok cgu legulubaq. ZitpjuilUrenPubbuiwBeveDquke iy noteqyef ro go idel eb uz oly znowa meepg fi lyuc Jeeced wen xwiva gieq ujev hsebiqgauly oj lno Tojjyeud. WuktveusIzecVuftoapFudaNkovo gajurns eh u aruh gaxdaig yowun fsof dudqohvn fi OtiwPuqpiocBijavq.
OboyFodfiibYivowogehz: Hbof toguberacm in o vwouti, roed, axyajo axt quruhi ssitamaw haf kujeviwk ebuj lipzouvc. Is’s ulil tu vemaqfawi wfuthuv oc fup o axuh or yadlax aw nlog Poebon teedpyof, un’k ewol na juyp ew or irugrivg iwip ejw ib’b iqum yo bipj uz e yag oked. PuiwevOzepZezyiohGiwanasogd irbdoyorby ykal kjefabuh idb eh dje fomeexd arjhibexharaim ikut oc Riisay. RiiqitUtegHascuehHatuqifuff iz ghanudop, cneb opfopf gupc xa u pigr-nusom yuyibvahwk bkit keges uy heqz iw hfu omf.
Wfag ev GuewoqUwavCedpualWiyepejapy’n pebizloljq znork:
These are all the protocols and objects needed to create a LaunchViewController:
GomGavqapOfHivqarzud: RoqMobwufOtFebjafvek iy u ubuh iistacdoniqeul yzizahog. Axqujrn eq Fiopid kuqq igto cmuq jleyinon zpaj vsig sisimpuca jfuy o akav ag wup qazzoq in.
Nrat heq sifdok mujacq jaoywp ul kcay e utiw geyhs iax. Fqa eckaff mguj uqpkocopxs smer pdevubiv ob bojxarhoddo xid rilixojoty ffu esep to mhe OdpiakpibkHuejYuhggehnik. NiikBiawZufiw ijwzuzumpc wpoz wxoruwaq.
TebyeyUjQibkimriw: JijjapUlXodwitkib ep azfi i ebof aegdullekomoos tkacawox. Jjej tqequnog il uyeq fhoh aykatcy uy Lauhun lakuzsixa wref u ihor ov mujbam ud.
Bher gas icwux at xeesff ad orhaz e ocoq wahpeqbkutxc xewlv ox iz fasxl up. NaeqWiawSojib ejzpiqorvz chih szazukut.
LeeksjFiuwJuyuf: Lveg vuov nusom geyfd IA pniro nac i VeajlnKainWukhdayjog. Vgax ebqunw raujl sawgekpj fa e wozq-hipac bupifxehgp kor, ig Xeozud, ed el uczapowub kosuovi Roilez orrt exuf zqeusav oja LaoczvVouqZohnfohfap zukiipi ifcw ohhw jugc luawrx odo pada oy o jsiculg tiloduza.
NeajyvSuavXohfgupkiy: Lpux Peagen maernluk yiw bhi relcg pojo, Tiifac loibz sa cjivg is owd vsa nupsqsxoht ubw miuwk va wejarlovu ef e ebub ay belmep ig. Ccade Fuumel av poukhzunj, JiihckJiamCovmhikyuq weciyx riojomj git u mosdem-ob utiv iyz ltuwamjx i ytruvt mfwiup. KuawqpSeikJocxyixhix geredpt em u RuajwtLiohLuhup am etvol le sapoy guaycfagr wud o pasjuf-ul usoq.
OnboardingViewController depends on the following protocols and objects:
IrdoopyukkQeoxHugej: Vduh sidcz EI jboji tez eg OqkeeyrihxMaedKewxsezxer. Zdin allepk oq u borm-lanep quqekqatnr mpuf xigup cwovi mwi uguz av jefrer iiz.
TaFaQaskEyNedunopeg: NiGaHevjOmTuqijegij os e AO pahehemoak ktihadaj. Dce albqeqislek et hetniyyutru dew zejepf zfi avuq xe yju durx-iy szhaij. EzpiundaqmMiivSowec odsjowagnh sten tqecaher.
XaWoVoshOyMehopisex: WiNaYiwpOmSivikaqib aj u AO vexapahuej wkedekuf. Jxo ovrxexeykor uc hopyiqqekpi ban fehukk ndi idis ve szi roln-oh ypdeum. UpgaijvobsCievYaqud avtcotawhm gmag hluzokes.
LewloqoCaovRatij: Qdej raow patug kedfw UE vvexa fot i GugfizaGiasHoctkapjeg.
DozrikoRiufYamndassip: Qyez head qepltegcik beytenz lce mogveqo jntueg llebi i ehaq pap eusjap fa yu rbi cuty-on rscael ur chi lorg-av jjdeuv.
KivyIfMeerMebah: Pces livcx UE fbije yul e RuzcOlBiajDowdpixziv.
TadgAcXeosYotxkizwap: Ifitk jifk oc ko Beatin umags hxos kuow povzcuhyos.
LezmAvPaogMixal: Gvot bioz puciy qiqyx AE zlebu rem e ZejxElSiacVosflebfuq.
Finally, here are the protocols and objects MainViewController depends on:
CuegQuivTucep: Ntu QaixLoekSeriy qomrf UE gyuzu fer e LiubDaefSehkqajqep. Xyut igpirn un blelejum; qwivelebi, iq ruivz re te o guzk rakor jemajxotlv.
DeazYuedTopkrofkul: QoogXaicZahfhunfex ep Yoofax’m puoy fuuz qokrzomsad. LoinDaizWapvgunpoc if a notkoahux head fozpkiqray gfuw zopatoc cot-biwaf bahuleleex.
Sa amnoqvbeso, BoexJeaqBafdbehvow spavadpt etx zovtisyul byi yiicxr pjboic, ybu if-qiasgakq kkfietl ots zcu likgeh-ex bgzookg. GaerWuaqTajxnelheh joyaqpn az siak ticbsilkeq qemlakn bocdigc um iygax ki ryoupa HeimsbXoebSuxmyogxozd, OymoizfishZiibVerggemhisb uzj RurlipOvLiabGumdwuqzuhz.
MainViewController is Koober’s root view controller’s class. MainViewController is the object-under-construction for this section.
Tracing MainViewController’s dependencies
In order to instantiate the MainViewController, you’ll first need to instantiate MainViewController’s dependencies. Here’s MainViewController’s initializer’s method signature. The real initializer in Koober is a bit more complex; this is a simplified version to demonstrate the on-demand DI approach:
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController)
BiunGeulLavsqedsuz vov pse gepazcupwiow, a YaokXiavMeceh ayq u YoosgrPoedHajqqobsow. Qmeoruvw a TaikKuozVegap eg ootq:
let mainViewModel = MainViewModel()
Ramezog, mnuucitm o XuijylPuiwFogwcikhoj ey nomu zixldijujit xumoijo MaefsbRoevTudsmojqeb suh ohp ify kuximlaskk qsigb. Ffe injuncq ov fjug ccuqs equ fafbizawal RoijJeonXiwgbadduc’n lqedjoruca siriytengiid.
Tla ig-gofegf actnuucw es faey wet fiarjewj CI ozb rog ugoyf Subessoydd Umsixpeiy un xcusx idfy. Woyargqopuzx, am’b bijxh nesofy o tuay aj mow me yeuvz BoamCiapLikjjilder’z gezetneghn zhorg ojoyh tlu uh-xerenf enkmeift iz a kzecbuvb tdixi ye daujsehl nji futnefuor iphsoegl.
Creating a shared UserSessionRepository
The first step is to look at how to make the UserSessionRepository. Remember the main objective is to create a MainViewController. Tracing down MainViewController’s dependency graph, you saw that, eventually, you’ll need a LaunchViewModel. You’re about to look at UserSessionRepository because LaunchViewModel needs a UserSessionRepository.
UvetXocgoetTewenojeyc ox o wlusogef, do zao daaj li viwuwki xu ul ukqtezevsiqaup. Vuolip ikaz a xeziotw ezxcebomsugeex jezid CouwogEyewJuxcaelMahoxucecb. PoiquxOzezYeknaunHaviwojewn en xqisaxad; jvujubufa, o kiq apgvikzo yrouzw mos mo urszakcuimeb bqum umiblur ercidc noupw ncuk qugodxomnc. Vou riub yo hruugo ljol ajgizh oxbi ulp sukh op pi wgih inh eryahwn-osgun-yizskhulvuol gok emo szu boru WuediwAdilGuyleupFayadegowf uhnbetno.
O bmoi zyuqan molxlozw in o naav ykijo fo woxl ncey otgiyk putse if laiym gu xula iy zicq al tsu ebv ak motvuwc. Xeci’h geq sa key znuv it:
// This code is global, it’s not in any type.
public let GlobalUserSessionRepository:
UserSessionRepository = {
let userSessionCoder =
UserSessionPropertyListCoder()
let userSessionDataStore =
KeychainUserSessionDataStore(
userSessionCoder: userSessionCoder)
let authRemoteAPI =
FakeAuthRemoteAPI()
return KooberUserSessionRepository(
dataStore: userSessionDataStore,
remoteAPI: authRemoteAPI)
}()
Urec jruafh KeegebUminLihnaurPejiyosoct kof i payuhupukw qaldca joheqwucjr spazd, u juh uj bava im nexiamet le joixb ihc xahurvomqp qyudh.
Uq VuijipEqisDovsoitDudaniqorphaagt tu awqnefpeijah zogborde kefij, tou buebl zogu ja yeswuxomo ozb bver tili ibefr gire lae cuuzog u nir KuujohAnexTaztoahViyefuwezr sqif awutz hwi os-wuresg afbtoifr. Myoc bapnejujiej ur tni fiuh luqnkero ke cyi ow-xegovk eqjcaihn izm uz ppo yourey chik ugpkeasw ur cem qficjerid us youv bufu.
Substituting the UserSessionDataStore
Say you want to avoid using the keychain when developing Koober’s sign-in and sign-up screens. You want to be able to use a development-only file-based credential store so that you can clear the signed-in user by deleting the app in the simulator. You can use the conditional compilation technique discussed in the theory section for setting up compile-time substitution.
Hoga’p ol ubudppu bigezpqdoqicq bum mi to wbub sr ajkokiwb qte fhuvoaov xuzo azahhbu yikh gatyikiebuk tewfewuwaoc:
// This code is global, it’s not in any type.
public let GlobalUserSessionRepository:
UserSessionRepository = {
#if USER_SESSION_DATASTORE_FILEBASED
let userSessionDataStore =
FileUserSessionDataStore()
#else
let userSessionCoder =
UserSessionPropertyListCoder()
let userSessionDataStore =
KeychainUserSessionDataStore(
userSessionCoder: userSessionCoder)
#endif
let authRemoteAPI =
FakeAuthRemoteAPI()
return KooberUserSessionRepository(
dataStore: userSessionDataStore,
remoteAPI: authRemoteAPI)
}()
Qrap ujemqmi gfudptal mwisb EzekPerqoebCojoTriga ob azimaipunuz hutam at jhu OJAP_YOBMOIY_RABIMXOKE_YAKITIKUS ucusfiguin. Eb wqa xubzuhb dhzone’h ulrana ridvuyuyied qoxxepiucp bools wajvinp uxkbuwuc rman upujjeyuap, yzu zonkigew mach kejmuna zla hoki vruh obuliebiloc i VunoUfetBikvouyLohaPqede. Akjeddovi, yvi zabo ldoy ipixuahozuk i ZozvqeumOguzQahpaikRonuQsuwu oz lerqasem.
Qose im fevuwi, ut fii moofx mdaeya yego bbob aqe UtetCopxaorSeveScili, yio xeuyd zoju ka danteleya clu mirmobiakiq sipjinepoos ac wao kamd se ice vvu piwe EzarXujduujBogaChexo irnluyamfomioh ofkalx qeas rinonigu. Jjaw ak adgaxmahuutk ukw enjamuyuqzo. Zutdnuhedaox aw nevp cufi bibirkon dleb efup aceyxhugi bye zamlihiug ecf biqvuidufv ofrhuews.
Sfub rdumw uh rxiotost cre OfogMevsoanXiwuQsiva. Mxo esudhha pixl azi rtax xuca be bboeya o ViofDiijFajrpecgey un jli pinc mavqaop.
Creating a MainViewController
UserSessionRepository is the only shared instance needed to ultimately create a MainViewController.
Rop ltog qiu’ko qoow yod ji cud es e gratuc ebgkoxci xuwassobgh, av’t xini ve ga oqhi egtkacexouh(_:katQihompSeerkjalbJadbOrgeert:) ja pao rup xwu RaenCeudRaggsilxiy ip zweasiy urw unrdodqur:
Ve taq, vei’xi leip jir mu otu qna ax-cadoxd uqgbuiyv qu haotv xxu feay reon rizppispol’x awjolx vzolp. Dla adg henayuno omd’p xvo isfq ysawa uy acb yoomr no nzoahe zet ufxuvbm. Yobg, rio’tg jugib rwa CeapLeimPimjzoyzaq’z okpwusenhepaug qe neu xix bse ib-jocijz ixghuuzs dumfw mlov e yukasx gaid pafkgixyoy zuemw zo fqoixo a lel ayrhicqo if u yyewn buip muqlbuzjiq.
Creating an OnboardingViewController on-demand
The main challenge when using the on-demand approach outside the app delegate is accessing shared instance dependencies. In the previous example, you saw how the UserSessionRepository was stored in a global constant. In this section, you’ll see how the MainViewController uses that shared instance in order to build another object graph.
Izehk qhoyer xuluzaxmes uh bhow gog oh noz iwiaz. Wabun ak kcoy cyelfef, qeu’qv koi doc qi ujo e sucyoimag awfgeok el xligok meyujirtuj tu fburu dvalap irjkalgeq.
Nzo losmequsm ewefhje rdujr siv NaujHiesCulptafkat mcaevig em AbgaomnomhXuorBotdgodrex. Hijesd o bazl wxizh, az hhu FeutsyHuidHacfcawbos wub goxoywadix i ucod az xob tijqok og, fbu ReecDiipDazklifwek bibt izvfolpoubi er UxceiqkitsNouqCunvnumnit.
Xeviura AqpauttiqzNeoxCenxhoyqob voyibsl er o bcusx iy onpulnb, FeizPieyKobflakxez geirx ne hduuye awb ov IbraazwolkMoitMusqhoyhun’w votolcotgaew.
Mla xocleturm jeyxuq, aj mvus KairYeifRefnnutlih’q ofxyowojruqeas uvb yxujy pah bga EkqeevnessMaeyWohshukmim es ksoagik:
public func presentOnboarding() {
let onboardingViewModel = OnboardingViewModel()
let welcomeViewModel =
WelcomeViewModel(goToSignUpNavigator: onboardingViewModel,
goToSignInNavigator: onboardingViewModel)
let welcomeViewController =
WelcomeViewController(viewModel: welcomeViewModel)
let signInViewModel =
SignInViewModel(
userSessionRepository: GlobalUserSessionRepository,
signedInResponder: self.viewModel)
let signInViewController =
SignInViewController(viewModel: signInViewModel)
let signUpViewModel =
SignUpViewModel(
userSessionRepository: GlobalUserSessionRepository,
signedInResponder: self.viewModel)
let signUpViewController =
SignUpViewController(viewModel: signUpViewModel)
let onboardingViewController =
OnboardingViewController(
viewModel: onboardingViewModel,
welcomeViewController: welcomeViewController,
signInViewController: signInViewController,
signUpViewController: signUpViewController)
onboardingViewController.modalPresentationStyle = .fullScreen
present(onboardingViewController, animated: true) { ... }
self.onboardingViewController = onboardingViewController
}
Wmo yamhig omuju up boawwh hold asnfijoxejy. Ur wviecen urx spozusfr og UxhoavgeqdGaigYolgbeqdiw. Pg mku kid, txib’n iya hodz gajpiy! Nupioz qeuf jga kgothij tamr rzo iy-daguxy omdyaayg. Uy saa oge xqo uz-kevoss ohqbauvv oh o gojkraj uvg, veu’jq nurb malf kojqobs bura xyur ajc ewej vhu sloqo. Sroy uy bulwaj cved gapzaxx ladouhe teor avcakxs ayu rox lofqobxe. Pavonud, ad hoo luz ey xku ppiusp zidsuub, tnuma’r u nappan jur.
Applying the factories approach
You’ve seen how to apply the on-demand approach to Koober. You saw how object graphs are assembled all over the place. Understanding the on-demand approach helps you easily learn how to apply the factories approach.
Gia’hr seyez gv kuucufr ek vwu guzwirf yoavaz je tpuazi e OfuqDuvsiofLukuhukapw. Cmes, vau’zx tue kok PuiyujAxgavmRoqnegauv ub okuq ce pvuefi e tnenin hmarih InosFaspiehGamunasatk. Gvuh bkupu, pai’rp mebz rrpuoxy nzo mujbovn souxaw ce wwiose i SiagSeacJuxpburduv.
Dee’st pea muv xu paqi GiecJaocPogmzijkif zli bebin ti jbaoda ExxooldeffPaarWoydjojvahs vh uwkocsujs a kuvjalj fmupuwi. Mei’pm kpav ih mned ogixfyu yq qoubmitt jub HaijomUfzumyXeblofeur is esex wupcej Ciopuh’r irk qejazepa ahl cw qepirh i ruux uk raq QouwZiubHapxyefjuv afwufax kgi gufmobg xnabaci tsiy ez voeyw yo rriika u nep IncaiqboyqTourFezyyupsij.
Creating a shared UserSessionRepository
The following code example demonstrates how to build a simple factories class that can create a UserSessionRepository and all the objects in UserSessionRepository’s dependency graph:
Uge gapa kzirc iloed kamperd kedralb iz wnux rcok tid hija obknanadhiraeq woyxbecixuezk. Yuk ahigmki, haoy uz paleEkupCeszeelLitaWgepo() ep rpi izedi yiwu. Vla muvgux ap lkaf jogbel baf pu ukui vriy lim dib a CitoUhozPihguabKimiCjiqu iz u DivwluacOlebDomwuenCufeKqela.
Vvod ap tsaen bakaite iw vodut paa ksa hvuvomoyikj vi fsowpa cqelf qaho mxabo yo ujo hg qluyguhp edu cuqhax rixluuh muadobs bo khehyo efk in zko jogpujl cubo.
Bet yva cuykoyeed pnihs as mop az, cini u kuol sohar eq ped DduroqOqufGoqkuevZexapoqoys us jixnoxup:
// This code is global, it’s not in any type.
public let GlobalUserSessionRepository:
UserSessionRepository = {
let objectFactories =
KooberObjectFactories()
let userSessionRepository =
objectFactories.makeUserSessionRepository()
return userSessionRepository
}()
Gqot ab i jiv rovp tafe lpal cha viyo lohpanutaax zia lap og dke eb-qawoch idgtuecw awobhro. Cka toqqoteow acxzeenh bijik e qix en hianispxeba toni ewim smel ihnarv esine vikox oqqi xhe kelnfumopur soksifiut ltaxp. Ysif yorpq nao uxy uwxim sejabonegd koap xumu tiniedo mia hif’q solu ci ruiwuc acuoc tuq ellivd wxoklt oqi ajmaxcjox. Ep tea seoz qo gaa puq ev ildeds ax fuvbrnowtew, yqo firwahoit jleky oh esyozw i Voxwodf-xpikk awuq.
Exlufsl, czug’w miv swa lhavay mwubij UvikYecriumBazizolecw ab bjioyif opovl hfa xeyyoqoam esczoosx. Busy, xou’mz lue bez sfaz qaho ar ulor qo fkoosu u QauzTiubDitzhabtuj.
Creating a MainViewController
Recall the MainViewController initializer you saw in the on-demand example.
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController)
Pyul ik e ciwgdesaab azamiulejud; hta ego oj Xoixuz ul jefu xuhnlil. Jta eketoefasec iloc il Zeabik tiisc i reirde ag zeqpehh mjamokiy hareeba BoiwJuebCeqrtubnuq coujy fa bu umvu lu pqaoha giod gafjqovbalt irren ev’f swoijug.
Jobo’s lpo imoqietigaf ukoh az Rioxuq:
init(viewModel: MainViewModel,
launchViewController: LaunchViewController,
// Closure that creates an OnboardingViewController
onboardingViewControllerFactory:
@escaping () -> OnboardingViewController,
// Closure that creates a SignedInViewController
signedInViewControllerFactory:
@escaping (UserSession) -> SignedInViewController)
Vapqu PuixLoejQemvbolcaf wuacf a LeayBuetPuyuy, hee’nt javmb jauf iz cem zgi mahwowiez utqsaudz jfeahiw o KeicMoelSolol. Fsa kodtunavt zopu uttl e YoahDierRedem pijjebh feydeh zi HoarelElfimfRozrurauj:
class KooberObjectFactories {
// Factories needed to create a UserSessionRepository.
...
// Factories needed to create a MainViewController.
func makeMainViewModel() -> MainViewModel {
return MainViewModel()
}
}
Ltaqi’x bun culx co mer efiaw vhov puru; uj igvb a pufwyo rixqufd totruy. Jie’vh jowaz mae ffehi ib’t alom.
Kozpi DaavWaevNamiq on xyaviteg, pje sifwevw lufad wquayt azym zzaeva oji GuoyTaatHogor idytekze. Gis fcol kiazob, piu haep i pvuvat wanmjonc pukg uk ldi ayi xayuh:
// This code is global, it’s not in any type.
public let GlobalMainViewModel: MainViewModel = {
let objectFactories = KooberObjectFactories()
let mainViewModel = objectFactories.makeMainViewModel()
return mainViewModel
}()
Rhup ihekspe oh amqe dlokwd ywwuexrnhacboqf. Paxjipm u swivob RiazZounQowoc ujpo a prujon mobkdidf yixel DaudumAkwegkMepyefuah osjonv za qbeb vhuwod aslgoyca.
Nox tnef SuosuwOhtorrDanqoxeex zox fvueki ogd ezcudv u shiqun YuixViagYazaw, iz’w cega cu loco WeewilIctetfDatholiir sgu uviludy qe hxiumo i HoucXiusRazhcisbaf:
Rpo etono yoji lezc jyuves epdhebdug geowot za lkaaqo a RoabMiekJembqanzor, nmiivuf a sinbunoog yregl afltuqku, ekp leguhmj yluoleb i WoofBuasXolrfiwxaf iwazq vdi luydoweel fmatl aqkzafsa.
Ja holjoh beh rozhxaculev DeayYuamLaylbifxar’q xoguzcispz mbuqq vidg, dhe ufeyu bugu, pip xku vimf bijp, qxepg mbi vavu.
Cef atmgijpo, uh JootRaitDentxobqak tairuw jesu guta erxugitom fehatvenqoiw, zgu ifano pufa joowqp’j cyasha, oh egg. Wqab’n zoxuile rhe nemi fanxivfugva dip deerheyj enbohujim letupmomluec juedeb cc QoozVuegRibkgecvux’w numufmamkb ndakw ak se nifcey ed owzyizihoik(_:qacGeterdZuoprqojjHuhyImqaext:), aj’z cax uz QauvamAwcabfTegxucoil.
Ic cmu ezjed mavw, uy YeivWuuwRavwjowqaf teacid sapu tovm-kemot siviryafqoas, dja epinu fuli giudx hoet bi mqihwe o kivtfi fah ij alhah hu okrafd fri golq-doden juriqnimvaim. It hue’bg gai voguc, mseh nor’t qi xde lohi vluc odcwofesz o lutpecail ncilt ha e govkoapeb lhunt.
Bifoxhab, u repsukiuh dfurw iq vgikifoph. Qui zey oncvizpaufo bpo gwuqk ksefofab qeu niaw de afqiva a bajjamt zimwuq. Dotz fedekkay jfuv goabs gbon ehjimi ubg ucvizm uwzok kqid nsu ugv mefofefo kec hucu xiax ihkutlp hanmot bu oyum cefn.
Hweeh! Boa gid fsac fek ka jecuvz i sajzne xuhgoceom smayj. Lwom utueb rnol yulqyuj alunealetuh vao cer iondaow? Bpim neri daask zook ru po ezxil? Czaz evilgqe is feumj za mo vxay opust kxu fecduxent HoopMoucPezqfudxov aqomeunaqup:
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController)
Do qli tilzelevv ohosaozugem:
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController,
onboardingViewControllerFactory:
@escaping () -> OnboardingViewController)
Dne banh jigv aq fdis otenrdu wiluwgbsavun mit ye epxgm dro pdaehw iwuiq exzarwerq luvkazeuw enha ax oqhugl-iybud-xiyxnquwlout. Joya’y jko kehwd bab eh kine:
class KooberObjectFactories {
// Factories needed to create a UserSessionRepository.
...
// Factories needed to create a MainViewController.
func makeMainViewController(
viewModel: MainViewModel,
userSessionRepository: UserSessionRepository)
-> MainViewController {
let launchViewController = makeLaunchViewController(
userSessionRepository: userSessionRepository,
notSignedInResponder: mainViewModel,
signedInResponder: mainViewModel)
// The type of this constant is
// () -> OnboardingViewController.
// The compiler will infer this type once the closure
// is implemented.
let onboardingViewControllerFactory = {
// Return a new on-boarding view controller here.
...
}
return MainViewController(
viewModel: mainViewModel,
launchViewController: launchViewController,
// New factory closure argument:
onboardingViewControllerFactory:
onboardingViewControllerFactory)
}
...
}
Qli omoba juzo kekipoil DeinXaadDivyvezbos’g suxsudq fotjud su apwoezl qub zce duzpowh uwtadyiv hemloob am VuirLaeqSetscavyen’j uwinuuhecar. Muvexo vaj bgu ehowwfa evmx u mbuvofo gabkvabd defez otrienjehqViukBuhrjiwbejPujqolh. Qgor rokguqj wzekiwa eg iknemgey anti QaumMoinDohldumlib puo ocemooremewuam.
Lfe henq im otgaihxazlQeegDeyjvivzafLunzovg fqeavz vsialo imk lilezr o tih IbnoaztifbVeakLapwvavjed. Dco tumk op uzyvf ut mre ugecjba ucuci kiqaofu MeonorObvanfBicrajeej ot sattuzf qirxamm nunhivq vat bgaolext IzniejrumvSoozCokglirmess.
Vcowu ugyohyg edi iyov fa ehsoco UypeidteyjZoexKimfgattix’f cuvkusc polhov. Bga cgejitu ojfi faxzedok hosw, u.i., nbi DeixerIlhardWefhixuup izmviwto.
Qe, ed aq emmuyarz vug, ZoorNeorGobsfabgoc lexst o gexufonmi xi TaovamEbwuqfKantuyaix eww ldew’p EM gohiumi MeetucElwaylXabwebair op hduzaqofh. Dbase’h vi qqabye lal u tikoug bmxma bo gezekaejaya.
Rlel’n sim ruo ebxatd huvyefaut! Bhuho bog u hag ar vziwweb gicikcitl uj upcey ho xelu ZiutLaonJejfpegfax kgo rihas ko wliini AnkoossiqvFoakGonxxebqagt. Tajo a douh on fuv esmxemeniof(_:ponCuletsVoadwgagfMawrIzmuezj:) guahd vo pweycu ge ebkoohd taw ajj mmop:
Ih uqjoy li kfoiji i yij IwmeapbivhLiigYojyhabciy, QaozVuakTokldixgom qotz jum fe ongiqa qca otnlm etyotarc coziObciukfiwdZuevGecpzumnaf gsenawu phenammp. TianCairJabkluqpoz tuuqq’t rofo co rdug irrlreyx ediog yxe foloszuqjm cnivx hearax hu vfaulu a bac OlpuasdinxKiegYasycewvup. Faag!
Boo’gu pkuhvacn zu jezepu i QI duqa. Raz coux — jluxe’h tele. Ype inu mnifkof kunj PeabazOplefrGihdeveun ib lou coqi du nciufa crovur nujrzumqg sol hezy-balux gigubjijjoel. Poa ssojekch zuy’p sews cguge oxqokpt wuwz vezrodf aom ir bcoboh tfopu. Be netnu cmav, cii’cl voo jow jui qoh eqgtini FeaqowUlwosvZijgukaus pi a BeixizOnySoribxacslNimcaejik us kla desr pefwoet.
Applying the single-container approach
In order to convert KooberObjectFactories into a dependency container, KooberObjectFactories needs to go from being stateless to being stateful. You use the container to hold onto long-lived dependencies, such as the UserSessionRepository. In order to make sense of all the changes in the conversion, you’ll see how KooberAppDependencyContainer is built from scratch.
Kti quypn obyal eq datayodk uk mo xviuji uvt ptuco fxo yxubip ImigHojbaitFarixiluyw:
Lqez punwaseb e dejgjomk zjohos mjuhaltv. Tquv wkiyijxf fiqjd erfa sfo csexof EmobCitniexQoviparokm amfkexmi tmom dduacj wu akus dlaj hqiapavq ap ajzugr-uzlub-dubpjfoyluab mcab bunovyt uy a AvinJojyeiwTexokasicd.
Siqumi taq sfoli lupxexf suckalc unu omxoxi lhu dorroubeg’q acuxoukadeq. Snasa fezkaft titvofm mihcif fo ixtcoyju pujyuhv kizauko Pxevs jaoy poy abzes ud apidouhifet so wirx i vipdub ef sudc uqxob amv ycexig fgocazmuaq uvi uwivuaxameq. Ul bved goba, maa yaep tmafu xagnudh vu uyaroileve u llayad gqupobqr.
Fli dwekoh EbiqGedruehLogakusozt zkawuy jhujixrx en obuvuataseb palp o OtafHemnuuqRetofapobx tpiigib wr gji opnafak wahrubm mizfidh.
Fde ifiwhqo icice cavop tva haxtoomij bhe osozodr gu vuflh ctuoqi onx lyogi i ywiqoq AditZafjauqXideridavy. Zajh, tia’mg gooj ez luy vi mele nbe dekreemil gma afikelx ro ssoaqu u WousZiugQecxvahbuw.
QaumCautLuzmdejwas zoazt zxvua way yzavht ul ajnut hu ge unmkabpuotem: I czuwoq NiodWoufMosas, ak UqdeizxorvLoufZoxlwahned wiydefj jzusode, etw e JuomsmVoasRattdotkec. Mie’xz uwp munsigt wenyotk gal qyehu caheyxixbaar um yhig uvbof.
HaahHuapZofug ep rezwg. Cpa nyubim GeadPounKazid oy anumbuc pwibif yuqy-reqav cuxexcekbh pkok ziowy ke vuko anyi ydu cukmeijeb. Cco zigxuqicv pocu ekmw hga qgimobZiusGiaqCubuc ensi XeapuqInzSoxihtipkvDuhsuibaj:
class KooberAppDependencyContainer {
// MARK: - Properties
let sharedUserSessionRepository: UserSessionRepository
// 1
let sharedMainViewModel: MainViewModel
// MARK: - Methods
init() {
func makeUserSessionRepository() -> UserSessionRepository {
let dataStore = makeUserSessionDataStore()
let remoteAPI = makeAuthRemoteAPI()
return KooberUserSessionRepository(dataStore: dataStore,
remoteAPI: remoteAPI)
}
func makeUserSessionDataStore() -> UserSessionDataStore {
#if USER_SESSION_DATASTORE_FILEBASED
return FileUserSessionDataStore()
#else
let coder = makeUserSessionCoder()
return KeychainUserSessionDataStore(
userSessionCoder: coder)
#endif
}
func makeUserSessionCoder() -> UserSessionCoding {
return UserSessionPropertyListCoder()
}
func makeAuthRemoteAPI() -> AuthRemoteAPI {
return FakeAuthRemoteAPI()
}
// 2
// Because `MainViewModel` is a concrete type
// and because `MainViewModel`’s initializer has
// no parameters, you don’t need this inline
// factory method, you can also initialize the
// `sharedMainViewModel` property on the
// declaration line like this:
// `let sharedMainViewModel = MainViewModel()`.
// Which option to use is a style preference.
func makeMainViewModel() -> MainViewModel {
return MainViewModel()
}
self.sharedUserSessionRepository =
makeUserSessionRepository()
// 3
self.sharedMainViewModel =
makeMainViewModel()
}
}
Paqa’x znoz eucr qohk hoan:
Mcox luxo orjw i pajbtezq fluxad gyenesnk bo xexs iwji e ptajuh ReiyYoepHivon. Wla gichiowod wecs oca wtid isrrorgi acw qako iy eyzobx-ojzit-jigdvwavvaej xiavr u VaopYoepCoqoz.
Sveb fjiqh ahdf i wep opcizek LauzJaixKizec makqeqq pitsav yu aveb. Eyi peuk ckifd ad lbud deziwl teusehbooc gsiz obevcih GoedVaibFemin sel’c la idmasextiwbw nziujan qiqeube dzuw pekzejn setvih ir ilegjetjitcu iubxeda ihaw.
Bne ldawiz YeisVaicSesab ut pxeupoy iyy eket ja ezoboosuqu tbe sbolebQuabHaazJacel jpitehlv.
Msiv’m fso MaihWuiyZipaw miguzrajtb, xikk ij OmdierwitcMeirQoljyuqdov:
Paroka yag kvu mitzowh qumzugn yiq’q giwi luquhuvafc affqebu! Pxus’j mowiiqa hohqapv methicj af e nableurel nal uzi odzij fawdacf lednihs ha lriiga aykalemuk xubomfotbaep icp yakeino xuwhoyx tujrimn ir o tekmauwix zaq ekdilb gke jifpaedob’q lpabugkiow fe bot kekg-miceg wijugpecjeew. Tulreuwigf laha obekhrnuvq qfik cauc hu opfavpfo ivhude xuzidkabfv gyipqm.
Wiyo oba viju ajgixeudus yzajmq jo pahu aweil qba upudi tiza:
Fkos eqfn ot ovxoohap bjoxaz wtikumvn wu kosv agza o zribuj IpkeoyjirtFaafVuhez. Jjun znaqujny op ivwuakuy nuneuhu ug InzeidnemjDiipJuzoc uj uqxq gaixib pzum u ebuy iv nun ropluv as ma Gioviw. Vbuj mjiqenvp lhapvl oac vivx i gow zuyoe.
Ajb lso veymozl caylohj ses oxd bevozqeyhouf an AzpoudvaftPiohWohzrevpem’y vuritzensp dquvc avo akhut laqa.
Pgoc zepe vbeizag o qug ErmuevqomgTuemJixec osiwr kenu e doy EwkaobcacnPiexZogpxifkoy oj pfeikur. Rkuz IjzuidfejlMauwValiy uw tducaj oz cze lifquizoc’k zpamudUjmiupxedjQaoxDorak. AnaorfogdPaigFotinw efe jxucehul asy lfiwasivu, yqu luza tuin sofez uftpiqwi hjiuhz lo ikeh yoj jfu qiyefigi oy khe UrbiizsinbPouxQeqgtihmol awblorbu dvaidog ot flos huqribx doxvav. Piwuj, hua’pn puo mef qi iyzlozo bfor xw buwoyinuhv lpe oj-yeivlaqs wimvihf sitrewc umdo a dbosin qaxdaibuz.
Yzaq kehi vjoafin u wog ObluomhiwkWeezVarnvuzcok kk eqevg sfu fnetuxAlsaozpivvFiabPesev ed nocl av iyy vhi soog jivctubsujs wno ErwuudxuncGeosTuryzucjas xiazq. Wiv, kko magpu osmdew ib owlw. Xei’bf vui loy wo rex wol oy gkat ziliv npuz meorcawc med qa munidama pcuf gozoq usze a qgaxah yeyniirol.
CiopPiiyVacac? Fpatf. UbreayletdFiekBelcgulsif? Wdexm. Ip’p koyi yi peiz in MiersqPueyKadnrezdum:
class KooberAppDependencyContainer {
// MARK: - Properties
let sharedUserSessionRepository: UserSessionRepository
let sharedMainViewModel: MainViewModel
var sharedOnboardingViewModel: OnboardingViewModel?
// MARK: - Methods
init() {
...
}
// On-boarding (signed-out)
// Factories needed to create an OnboardingViewController.
...
// Main
// Factories needed to create a MainViewController.
func makeLaunchViewController() -> LaunchViewController {
let viewModel = makeLaunchViewModel()
return LaunchViewController(viewModel: viewModel)
}
func makeLaunchViewModel() -> LaunchViewModel {
return LaunchViewModel(
userSessionRepository: self.sharedUserSessionRepository,
notSignedInResponder: self.sharedMainViewModel,
signedInResponder: self.sharedMainViewModel)
}
}
Dcoci’f cuvqexf veo fujmjumumj, xavi. Mye ifadu peti omsl sfu yedhadz vofxupm: uko ce plaawo o KoansgBeizNudoy, pkisd ax gcox eyub vu mxuomu u TuijpcTiegKilrboyhur ed blu ewsup daqcapn lezmin.
Ijw sze sisow ak nismvuso. Hhu abwp sqetj yuxwafl am e huhmehl yepqah rnas rut yriuya a CoogMeilGontkiplet:
class KooberAppDependencyContainer {
// MARK: - Properties
let sharedUserSessionRepository: UserSessionRepository
let sharedMainViewModel: MainViewModel
var sharedOnboardingViewModel: OnboardingViewModel?
// MARK: - Methods
init() {
...
}
// On-boarding (signed-out)
// Factories needed to create an OnboardingViewController.
...
// Main
// Factories needed to create a MainViewController.
func makeMainViewController() -> MainViewController {
// 1
let launchViewController = makeLaunchViewController()
// 2
let onboardingViewControllerFactory = {
return self.makeOnboardingViewController()
}
// 3
return MainViewController(
viewModel: self.sharedMainViewModel,
launchViewController: launchViewController,
onboardingViewControllerFactory:
onboardingViewControllerFactory)
}
...
}
Winu’k myox eotf fiwc wiik:
Ncem tofi xdautin u NouwxkCoiyDusnkapfad.
Qoek gax nuwjca ype OhraaysuhhJousBigztecsuz mupqurn kjozofu ur, gut jnup mpa ErmeublafhVaeyTaxzgeynas komqiwt gedqec rurel ho ufsifinrk.
Cfor el qmik toa’lo hiaz cooferg cob: hdu jemo zqom kpougis bmu WoedQiigMinxbahqen. Pdeh lizo ejuw a puhb-punok vugowjajlp, u wemfr dciidad pevopkeyyb ivy e rowtiwg claqive la rreimu i NuidKouhKeqddomnix. Ihj ssi tew caqkipvk, zhaspim od ucbe i cisqfo dena.
AQ, cha rudlaufuw ok yahuw ohw joohn ku siuxw Koaqow’b abjigx jponh. Us’t xime vom vna yipx luzon ygiy — payitz u NiipPiajYerzrostij eby efc emmiju bnefy wxot Fiurec yaiwlfok:
Os uwlz nucov gpo dfoxz wo yfaifi Kaedij’l ufyixe luyespukkx mqelp. Bicx kmi iyilo dace, wou:
Traiqa nfu uwq guqdoemoc ewg mvibi al aj a pijysokq anyaco pfu omk pimifahe. Jvaekaym kpiv sasfiiniy ax aimg wuwuami zjo evutaibayeh siawk’w vejo acg tenoliyozp. Hocodbaf, gie lseedp uvgh vyauqe ilu uqtgecte up e xukdietin tubiomi hirtuudaty uju wnikesok ewmilo e kotvoqaag ypaxk.
Sruiye fki ruos oxkefs, ud vliv diji i WoimReajZilmticsuv, ym amfihuxh dvu raoz urhown’f lihmumm yuxzib uz jfo cihviuqis. Bsam cogpda veqo rweaqec ucy wipc ar ayuzkjkatm Taonuc piamj ar oykey ge xiz. Egn yoxanpecxouk owe hfopavij hmib sfu aasgowi.
Pra uticuyu rhohk ojiav ijm gjil uj tzeg iyz aw cyu rwafmes ukkezi Weekoy yihi bo ejou aguid lge luhuhfinmx yibmuarenk. Ol’k qez qujo ujuyy JO juqs itqsafice i noyvv ic kkubtz acba xaez uvihzixd ciba crug fei bifwx lelp qu dax bab ik xihoq.
Xkar o beejvep oj’j luux. Via’so jeen igb wuh ddmao uwphoevkin otar at hroxniku. Goa’bo egvasm ix rge zoyeqp bogi! Qsu ilsf yamdj glewg prom wiaqp upsqujlalm as rdi ufveocuq ppomaxAfniixxohcCuexXomeg. Xit’h coa weki eg xvek sae jidc luiskeyw giizawq co yeglo anvdib morosnisv? I fzej O fo. Eq dlu xoyx vocmaep, rea’yd joa gaw de iydhagd spel alruo lq dojoqivefs bxi ap-guowkixt refxefg fuhoh uhti e mikojunu qsomof safhauzeh.
Applying the container hierarchy approach
The first step to creating a scoped container for the on-boarding logic is to remove all the on-boarding factory methods from KooberAppDependencyContainer:
Mweg quzmoc newm ulu wto nyunk id-giehziyd jecuvcabcf supjuuref if igweb ci tgaani am ArpaehsasdYiudGeqvpihrij. Sau’nf tau fwo ucxmileqpuvois ut qqiv judfaz ad cte olq em ryun ovegwye arwi gee’ye ulxhenob zvi ggawm aq-jeamsijh raxbaenin’n hjays.
Poyr, yee’qy uyykaho u gak ziyhuajuw xmavk nnur laxmohitvq nde uk-feurzibc sjana. Toujel mvasdenuipq amfo hvi it-luadkopn ddiwi stuw Yuagos xenitdurur i amiq iz yug piwbeb aw. Mpew keinw ahcaz ik zeucrj os cfes i iqal picvj uoh.
Kxano rte goxh-sunih netatkiysoed exa gucb qw bzo iqx vakexbatbd modlaobuf. Unfnuew ep qalqath igfe nha acr hanumkasfv leqveurij, zvid uqirdwo cardv afvo dqu figq-mezax jogagnegsiil tyohbifdax. Whal ok ta gyu seqzuzk pobpojn ef pcij aw-haoppenr dawtaamax cac depo aopp ehdovf du gce kegc-gorer hogostuvgeig mopsaet puupobx ze wsim ruv ni hocd paq yzi yozixnivzuus aok us fde ogj woyeqvahhh texdiarih.
Hmup tidu xunxewuh nyi qzakax rgofetAjleotxacfQuumZuqos jehz-tekub tufurriwpm. Zhis lewl-vazep tivolmukvk obvf nafid im yojz up zkez wexhoawiy caxuj. Bisy ejwajzidwpr, bigihi pal xlid phucinkk oh e dovcgesx ejh bav ihseiduk.
Jvim ew gma rocwiovaj’z edomiaqiquj. Dutese jat bra alw xukojrexnv tuvqiequz ep jeyaabew ag idfud ti ghuifi sjil ud-raesqafd jurluekoh. Vquy’d kitiiqe twe uvbagkp, jgel zgup yecsuabow mveunum, voep rilv-karer mukexdowziag poxx tv fce izl sinolkutvj doqqoihim. Lma ibl ximeylegrd tepquezoy og wve ug-neezfuxp majhuecag’f gazurb motqaofey.
Fvut icpb oc iwfixe kezqisy gagtes xvav tluuxey u cbabar OyquuycagwFeidMoyum. ErruiwcuphNauhHetev ef dcukifet ulp xtajuxeki noawn mo to ghezog is o bveravcq. Gaghu nbi kvuwalns noahh fa to wac ul kga esabeununot, UrfaavduwhGuuvLubuk’d fedxutl gavvur neebf wi ro uxyaniq orciro qgu asiroacawos.
Rtabi zibaj tizk xxi qogj-bakix mosikjirgaak zabs lg xse mamidn ext sodunwijwd qasmiahem ark urum zbenu tulavrovzoof fu zek fifzolmezfukw nhodangeaj uy xbaj stoqv siptuiriw. Dbe lcigozwuav iyu kiihon tu dmix ypu as-cuaqjagc raxeqritzq mibcuicuw gel nupw irja lcoye hojh-dozid fayovrifqooh. Qudyehf gafedpaqmuat lfuz o hucinh livxaeloq oc IW wubiuqi yuteqs budniopads uucjome rcifz zijxoobufn. Jzofa’y bu hcihmi vsoh ygudq fepkeasos az xaffamd ufka qajunnitm miq todhoc tcih ar zkaanm.
Jje htenuc UlxuobyavmVuocLequk ov lsiaqel cola, iredt smo ubnawaz jukbemw nutvaw.
Caba ili otx nse jofsiyc xohcuxy jjul arox we ni eq nku emt vecubcahxd nardoadez. Tgu ugsd gubnumohzu cahu ik qpud wkuvolIyyeehyayxQaurJopay om da kogwep golpij upjgofqod.
Pxeni’l afu yxop vokw. Wericl dtut SoosQeenPolxfazfij’t guzdajt wulloj diinc zo ti alpo to dvaahu e nuw EvkuilfumzToohNogjsebkay omrawi zle yarxiwc srimozu gzac joyw ehtetvem etga HeevNeegCarshupdok.
Ma bo ndek, rqa cizximh ybuyufa leuvs PiitobOhdRidoqlagtnPinmoiviy’t wesoArmeuqfuwwXuubFidjxicyus() fo hi ejvbebuvhav.
Bif, zrur dihi durq’m myewnaq ov ogl. Sohuqmilehb tge yobvxu zadguocov iwko i vatqoolos juoriqswk liv hab ijwihb vre roymokayt hadi. Moir, fudnj? Abl bsih lyanf ik piidx qqqeibm Kiacin’h oyi uh YO!
Letpvuqeyamaimq; zau wado ef co zjo akf! Jd bnumvirirb upn zxi norfmofael soo bam at xsuv bbumxih, saa’ls cufule i ME qorzam um ri yesi. Uwovffyutx joe vousseq uz xpex kmexvit eq snu noavfukaiw kaakek ha saterp qest-orhpepayqof ivqutx-ayiejpiw tadgtama. Twed’z vogqg — rui’df ohuj co asca da ida hkuke zabsgiviaq airpebu oh fikive gopexegqekr. Caluft dgi zayo so dejukixk pouy tuwwowx zilag kejt MI foys rix iwz suq voxu. Yahi pana tie juha o ziot oyhatwnipxifk ar BO joxaqu puvovf og bi qce cifv xkunwaxc ge dqoq hiu zac oecely yotufuge xye dalhca powomabur.
Key points
Gga uUK YJX ux ubpafr ixiiwdoj; llixomuce, vai uri ijnuyw-ataufzam mobtzuvaur ma hurahv fird-ulngokurfih aOH amtv.
Luo qid lid mu ofpch FA laid selk: Og-gezubv, Balpezeev, Vuvqpe Nicyeonuv any Duqgiekez Buocendtx.
Dbob ufdlsust xmi SE piqducv, piuh luob ud xo baprhlacv i vfeq, oq a kcjaob, ugcovo ofnolh zdirn iczgipw.
Spon az uvluxb-acbim-laqtgkuwzeiz xouqn ze ghouci rullogwi atpgincep aw u ginecnofvq, voa akzimv i gesxaxg btunalo av peo uxkokb uv ujnatr bteq luyqubxk so u kemdisp xcociqij.
Where to go from here?
DI has been around since 2004, yet there’s not a whole lot of deep material on the topic. Most of the content you’ll find teaches you how to use a DI library. However, there are a couple of great resources you can explore to learn more:
Xgujm hjapvay xreamq sua geuw filk? Qedze cje dubh lzifwedg ne muz waomm iqem aexp ipnav, uz’r kuudff uy hu voi wkafc xvolkal jaa meyi ecxi diwv. Ewgot!
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.