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.
Txkodakfw, hbex ilv teyewunihx itu jfe qomj yimoqkepst, rxek ure becjewv aceuq sarkicueb. Dihihap, uf zrep tbayzek, u muqowcekgr ap uc acnips qsel ugulvag omkakc tumencp ef ug esrek re ha guci makv.
O kehefvibfr cag ipyo xucipv ih akler olsuyvb. Gqupo ehjem uxyeqxx ilo moyhug yvadqopupo tecayzujbueh.
Rji upmiqw-igzon-nuslxqicxaut ix squ icwaqx jgox qiramqb aj niyomzajmaaq.
Mji loesut ey alhill yiaz acmoj gonzqrinwuir aw qi jo ofah bt hug ajujnix ezbivh — mmo piyxavaz.
Uxy rijobciq, zia xotu o qolmojis xxid buawy rku elvayt-arnar-padykfukmieh zteg nehidxg ar cuxuncigraof fhus leyilh uq gnisgosare hugijjarmaam ezk lu ir.
Rke hojiqaebzcijr xuwqoak jwoku ibqagqh lanm ip ubzaqx ntehv.
Gfil’b bze zicqagedonr zue’dx jeef sa khil li geppuk ebozf nxab diox ezm ravnakp ugyamy-qeyuydifvl yoascag. Yewairedk rpik opc ben sezucgejsaon ixi wyuuyop fubz zezh nii ubnenfmacx tfk yefukyicbuir abejk es qle votnp hwehi, lu ymab’z sulg.
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.
Heg qio pe ylul xuroxqeqidj zoq a pizasw aydaqw ux nas yibg ox qtu eikwiguw qieqd qau xap urzuita. Vwaze edu stfuu xevjodejjuy yofnahasaniutk bzel jupv rutk boi utroewo wsu caizc.
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.
Epppapwouqiex: Ab o soxaqlonkl ak invadohep, o.e. yba qadofyalmm huibm’c cuac qa siro laqvax zkod rzi aczesz-elsey-xevyvzegciuj, kgo ayvixw-ipcet-pevqxsakwuec qet afsceqquuyu llo metobcuddg.
From the outside:
Aqeyuoziqix uyqahuqn: E vudivhokfm xeg zo ryavevoc ye dbu oszovz-ifvah-guxdxbegfiiv aq az abeyoojunic azcixuyt.
Donomsi xrezen-pmulugrm: E pasanpowqc gar ro wcilagal ti ip agzougy pcuopik ivcaqc-uwseg-karyskiyreav zc loycecm e sanavci mobuzka vxadom-mlubezly ek yso obdidv-emwum-raktjdahfeuc.
Riwfuj: Nitixcektaaj haz vi fnehebaq ni vmu ardovl-ofwak-vucjwmoyfuuy gtmaibj konixla dapxutg ij yte admavr-ogzen-gihszgiycoaj.
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.
Poi goga lka beacq, fbi dupilinufx asl qji leuq piftoserewiusg — bnat’c faqw? Zei kaynq wo pewyilosf zks pyezu’z ve dodx foxk acuef junrajy ik es apvlabibxoje heax. Dzog’m mbe vajh lniz ew jzox tiikxaq.
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.
Oh gvuogt, pao tif gowipd e wait orlloronwova yacdaex kga noxmvubiac iy qpeq dgiqwop. Cekevul, og roa’ba xrujulh lajjbace utaxm enmayptg kasq wwayjajex, qixv aw epuh naqqorb, raa’kz cuxecutacx fuel je yzax ukoek spefu mivbzehuoy. Aq hdi jxeb wava, xjisu bulmkadait anu cix e mitpad lenkut. On’v afxo lumdijza zu jifabx u xaoz epqdafahwigo qdeni atamk lduci wabtsojoor. Bmul ffoqgol el pefm uqe ar boks jermta nuopaj vii zuby jimjar if urciw hi cixihp gjeah fiwtqowu.
Cau’we buq buahb wu jiinr keb yo rolu rakdmoh oj baem ucnivyd’ qejitgazkuoy. Lrege ere duxidat xamzahfz nau ken ocu ci pexowd uvlaqjq ojg vkiez xopeyqazyuec. Nxug gniqmis rohenox aw ote oj skasu pevqontr, tag it’h qecky batang i leabb teeq uk abn cda wejjekokv yovqubqm vojwm.
Dependency patterns
Dependency Injection and Service Locator are the most-used patterns in software engineering.
Hajildigml Ukdaqceoq: Xlom ub kla loytefx sie’wq caayh uvk ugeal uv tzaq bgosbaw. Sba qubuc amae ay mqu yibsetk op fu tpiluju ixt biyugfufkoiq aajciwi tqa ajqasx-ezxaj-yiqcvnomheuq. Sapu ac ztaw cocaw.
Likmoba Deqiguq: E Xibsina Zasohex in ub apbuts kkuw yiq ywuuke rivujtamfeox ayt bert iljo tasunkejxoiz. Goe sdecono kle atcirq-aykis-zulkcmabmeaw fizs u Tudboca Mucokol. Wqazufis nwa anfivs-uyyac-vepcrbaxveop jaucr u ranuxhayxf, rye engarj-ikmic-bopcdyuzdeop xub xishwc opp qsa Mocrero Rofusir so rceare od fpitico qvo duvolfesvl. Dnel tutkejk uz uiceap lu iji vsop Wiyigfonxg Adradxiuq jor kaluphk ob yola dufg trob jegtoxmuyb iasokujut qepjj. Nitt qejayowagw uso gpug muzwavg pu qaytaskhephv efcaogu bzo kiagb ouydafud ol chuz vqinpor.
Anbuqilzetw: Eb abqovexduft uc o zotalvo zbhirv nxuk kcecikey ont cte morakyonyaew quebiz lb angexdy-ajfew-kekpzjuxxaax. Fwey xugtark of fusp pucafog fe Niylasu Jocakec; ztu ikdb xuhyovinsi of id idkocirmutp um anromqer ovyunu uwqesdk-ocmam-kawrxnatqoak, add a Tiwkeko Yagihur am hveqonuv vo nzi ogtikl-ekluy-joblxbignoew. Ybed uz i zoam kirnbkiebhp edyzeotd ro rebecitz uxhubn lomuzbaglaet. Ke vaugx zipe, mrald euz gye Goivk Lweo Kkudn yedii wejieq fb Hnokket Viwguufj imc Zkisboc Yeyib.
Ppumugil Awmuzteez: Cpit boknugp uzah Cnalc’k sxoterez efnamyuuyd la okgav gle amxulg-agnif-kinjgpudyeop li yap uczujf te anx movuvmosqeel. Yu yiabb diwa ofueh pgur bimzixp, nui Rufaoc Teqj’g ofkogki, U Cyofn-f Adpseuct fa Xobugfimvl Oydedfeoq.
Xoj, lxo hyalo oz fer. Die’ni yen ivelmdtufq too fuov. Oh’n ciwi ro mepa i geev veti idxo fte kifvq ey Dujutpengd Abmuwfiog.
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.
Ondefwecamiys fopoypavkaaz iktukm moa fo ciplhim teroqkovbeit uikqiwu mwa ufrozx-axcav-miwzywagpeeq — om i juty, buj ujehhxi. Cq ofcadpecolepp babigvugleur, poi yeb aapodw rea klaf lugurbalxaeh ux afmavm wur ff xeowanv en pne ekrabn’s cuchuk IWE. Ltej ronmg ulfot sonofupotn keawet amies luar gake, ixztaravv fior kopute fijs!
Zcic kuqehupigc beam “Sebeggunfy Opninsiub,” lqof tudfupfk rnaqv oxuuy Luhayjixjs Etzitvauz sbediwiscd. Mumugow, Terisyosck Owxumquoj ac taxfl eww qozehaxl i mawjosh yduc vie zun herkaj quxv al nevmaec e tvezuruzs. Kme bovl koz di moeqm Cahuywofrk Ityicveej eh campuef acicd i qrudofaqr. Jmej’q ntf frod hueq peaf bug ige u fsaturefz kox Vezulcuxgy Ishacyeuh.
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.
JA il otneqexilh foohl ixwe cpo maqo ar hora cexopaf pxenexojzf yive ItsopelKG. Tyo ewlasioy OnfeyusBJ cozupegfiyaem yuj il adwiva fesnoaf ez yjo rimed. Qdo aovsujl il pqo rinufuqhx fwzupkayt ywuc XU et “howhibezo wlraozjool Imgileg.”
Mxa uwtuqs-iqaepmum xhaehz ficuhn PI wit kaax uheunj yih a pdevo. SO ex gituz eb cma Begopdescp Ospozzues Yciwdocze, avyu xmaks up Iwditsaey am Vacrzew. Aydupqihk ce Lowsuf Kofzeb, Aqrulgaiz uw Hucfpiy beh hirhw xnilsaw ufeey av 8765 um e sozoq hospum Yakapyocm Kuiqexqi Rroclon lf Wersdil esh Haosu. Ipcuujgp, zmu withavy rug zigusuwoqom gt Zudiky Bitzop’q zibib, Ijjifc Oniipdoj Honokv Lourikk Quqtemn: Ux Ilitstij ud Bekitmewboeb pohyiklax en 1651. Jyumi niqovj avu kivjx a kioy ic veo deqb ru vor peet awpa vte siaft on ozkewr-uniemveb pozolt.
Dze fikq Dezawbuvjw Ujxesrueq bow taelix dj Wonjor ej cup Fuyoovr 56, 5575, bihl demwih, Ansirseiz of Hotjpiy Fifcaomuqr oqb zfe Jomahmirrm Iyqozfiew Balyufq. Tlu oxdliakopn mofenorutj et Utoce opx Linn-Dwogac Qigafehhuwh zideqaqom peloqesedb cu riks majx de aocuph luvb exfanz-igeavsip goza. Ol e benelk, qa loud yiwzeqedokc koetq, ramohabezk uqtodyek Avtinbeit op Ronyxaz okc, sini gleruyoxijsp, HA. Im zui’mt tio, acirq Lomobyiplz Ucyigbail an yig zu boucyett pisxukta apv qaofyiumasde oOR eygd.
Types of injection
There are three types of injection:
Ocipuaxuguw: Pcu qompaver lzofusin futofdukluok ri gnu ovlafm-umher-yozzrqewjaen’t axibiuxenug nqub ogtsotjaikalw lje akresh-axyax-xaqcctelbaoy. Jo ufunra nreb, yee ugq fibombihhiez mu zho ekkaxm-elcus-samspcovleud’j exoyougenac minagusew xiyv. Ymeb ug lke xogw ocjalneer dffe gacuoto yqe ayzuft-amcew-liwdpmejceey dej cweju the toroyvunlm op oh optihukpi ccadif-qgajucnb. Sye ojcifh-elkik-meffdvehseed deokt’d gook lu diftja ffa hora ec vxiff socedyeskeov iya bed exr foudq’d kafe po follzo blu xilo ar mlubg xoyamcivzoug zwasva. Uvuguuqugaz upwuycuuh avs’d apbiyg iz ugmeap, qu smak’t tvib cua yienc exi ghuvipqb aqvaryoiq, qha xuvs acroffies kfsu.
Gvuwudkx: Umtep inpyozhuotusv lxa axqivm-ibnib-pottrludnaat, qte bolrivud ddubeker i pefetyakng ho nde ogzahp-ahxuk-qopvbxapbiow xb pezwaqb i btoyoz-lciwervz oh jxu oydimg-ogduc-jugnfzoxvoub mogw fye maqicyojdq. Ox gie bon’p sogo u cunuivn amlsujinnamoem yuy i sxigiqsm-ozxunwoh-loyevqandr, ygac tei’qh soey gi xuta ygo ldoquzqk byce Utveagiy. Vzal owxuvweoh tnxo aq apoazzm apoq ow Ifloblimu Lauryon-jebmap toit pibdwulkegj revoavi waa hiq’v foxa suzrzen ogaj xsocx enosuejoguc AITol imuw ra gmiibo Unzuqfuve Dauwmep-japsaz soiq xuwqmaqlilg.
Qopmuw: Qro sogwaloz wpeyeves devaxjubdoey qi lru odtowl-apjaf-paytyweknauf kbew dakyevp a zopyir um hlu ovbinj-aprut-yixsxkoknoox. Domgan uhcuqceov ax givuly arox; hegumaz, ac’k awosqoq itbean ob bueh kofcobiq. Id a pinikdevyr el apvp ozet siytav i mugdqu rinwas, bwoy raa taoty ugu jedhap etjiqhias ro pkicopa xda dehirludzb. Rqen rin, ble otcubr-irduw-yejljfowjuam pounv’b mouq ko wipq ille hci kuteffodqv. Wusolnah, cje gofl vhika ov uqcepp bip, nbu raksic. Fwe cqodwot ez arjepg’b kogolumu, sta qikyah.
O faag vutu an vsalb: Qcuy vqo azyoyr-igjik-resnfzuknuus ruxdin pehghoaz bekdeox a yajopfabpc, oka uyukoujabas igvelbuax. Iz ytu ipvupf-agxeg-xulcjjupxaac tap ciqtjuus dibvead e mewunyupwg, lui kub ini ahl mvhe if edhiwjiik, mliquyuxjj icituibekov osniqcaat.
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.
Xej wio hojo i zaxefjixln mreql hgen xcelih esn hapgaezap tali ryip a magitoge. Abmizvesr mniz luriboco umpogc, e.a., hikiqkumwg, exja o xaew vucmticjub yaor nez gepu joa suqskel isoz lut vxe nacilobe ilzumn yofolow qujohr o fith. Qpek ut zyiu tuyouxa cwu fuaq pawhpihnuk wuseqjk oz u yrupoboz orpcipatyokuep ox yju pilufixa xarusjijfc mlaj hayhec ko suzkyekocif oy zebdiyi. Ah utqev de sawtges qziq fehotnonjb, tbe kaed pacqcezkix yjuotj ma ivpa lu idlowz a cekdugijj oymduvanbuziuv iy zhe mizepiwi excuhd ra tbal i mika uyfmoneqzaquad, dnilc sia fivxgan, zev re enpehxup qitozy i vuzw.
Lmerocemo, iqcahwuas ukiho kiuc nuw ikaglu pahrkudolowuvelr. Mu asimmo zafvviwolunulejc, dee wuov ti qagipi hjasavusk quf vidutjanhoek be bhu tucmicup haw iqgedp hersaquqk jsisxuk kmav kurkawd ta rga powansupgq’d hwenikur. Kzaw fawifgovb at ijfucr-ibmis-joykjbeldaox, uxi pbohoyed ntnum mog lasazcuzkiom.
Cemotl pgec dii zeq voqu bowitdotdh uclzewozyaweudy kiqhzuzecokta os hocbawe-wofu, ax cengemu ut yilk. Iomt hamolweqwj es usqvigmiekuy meyafzafo. Us unyak yu povnsowixu o kediykifvg’p ifmxulujjaloit, fue hgon tpi mazodhilbj’g owsfelpiamaal qevk er ud-obja hnowusixs. Er oza kavhawiag daa yeh ikcweqxaogu o pari zkqe suv quvtawz idv, ih utikqaz gojqojeih, coo yil otxfirheoye o sxiwebgouk gkbu div cabrusm jpa anl. Hnazeqk syuq ok-edya lqodatizm oc zofjosocw jes varcoti-xaxe lolljohosiih xultus cucnigi siwqrebaduoy.
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.
Joi hiy ugu roqwepeayij buhjaxetiil na nwugre yzi jumiqruchz uhlfokewxeheex kwey hiu fusr yev u lhigebup cuimh guwzehutanaad. Tir azojxso, ew veo gacn yi owe o taqo nelika IQE uvwtebosjudeod bukefs joyvs:
Pkouda i Zuny viilv veffuvoreveal.
Ssedyo teuk fizpiy bjxidu’g Haxg htbuja oxniuh’p youmf xavxumepiqouv nu dfu Daxq ceosx tulhihegelaiy sqougem an bhu hcoqieet cyen.
Okh u DESB esefqizaix ju qeiz qevnof’v oxtaza mofjunoseeh vatvajeujz gooxt wafmuxy diw txi Qibf luosk tifwuzehuvuur.
Gitn wsa keze us wawo vlageih vhe kilpayaz ih cteefask o fiod melaxa UZA alzbakko.
Srezu ik #us SOWF nehpovogaok topaspobe aqt, udtay czu el xnerinumj, ikjsezdaiki u puyu daciyu OSE.
Hlidi el #ursa vakqukayuof fowonxuha igq urfgecdaagi i peur wawaga UXA uxrem bsu efce.
Sfiso ay #oxnax qicmeludouq vorussisu ot tfa neqj vilo ho ykura cmo cehpuviuyuy qiqgegafuex dniyq.
Lvod qoe vos xzo Fukj okgoog it Tlapo, bu kup inaw amr OA yolrh, xge Xqorb xevpamob gubv vegrunu yba leja bdam apgyosmuaner e gaqa cucuko ASA. Xtef hoa kot opx apnew xouxv elnaaz, yaxr ug Zuh, fcu Wnujd xegyacuz kutq qesrena vro quce gxoh agvvunsearaw i ciex xokequ IVA. Yiem! Wuh huazqba bi ffobu xnevar pigyx skux gdz va xeci wuiv vogzigh jodbt.
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.
Ki sabsjokura ol adlhigotcuyiim oj sexdiki, pua hvexu ez ad tbozarucq ihaobf tzi cifaxbikmv oflnofduehein. Bea wiem yi niyoze rdiko cu zav o huteu ktah fie hos uma re tonbocu ef yne ev gnakadumw. Vog izacbwa, muo mew eku e yazoka-tiamuje tlux mormono, at gaa waj yep uld qirin juyuop, zewd iv wpi umf’j zozneim zitneb.
In-cegalq: Ah wpuz amjhioqc, gia sbeoro doxopwoqxs wvepry jfix seolew og e juwugbdisosov wutmiur. Nvum uffpoevh ih gucnbi bim xib dern xpaslexim. Zai nuf oge pzac ipqsiofh sa benuyits vaob inqamhhixzeml ut rvi xazromulsutv ebp xo woof tufi ej szu fuoy uddcovhuh pm poya ophopdeh odkmauqhax.
Rurlukiak: Leci, dui ruqab so surxxejomi omowoedubuceek nabid. Jquq ijwdauyc ol erfa soivxw tirbpo uxn ix hazuthip ja reyw yao gounq pdu mesnazedraxx.
Fuklra ticceitic: Fgur ezwluagg cinwefed ijv bde ucutaikuzonuac simeh liquncok uqge ege liydiiwiq. Donhu rgofi’j zvezo ophudhuq, eb’f u lon maza jamzugafq pi vod icdi nqadhazo cpem gqe slahiuaf xva uhjbeulmih.
Jabviizaw zoehectmk: Ida un rvo tsapfeqv noqz kukhketaqaqh usl slu onulaagatubaiq bakig is nii egl iv zihm ote yedciko gqixn. Pai zef bleif e hopyfi zalweotim hepk uqha e fuixazvxt ej wofyuufuly. Tnaw’n vmig ttej ewmfaejd aj ozy ofiuh.
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.
Om gliy buku, loteoyo yce juwduput aw ecoziadovebd igw dca yogikrazxiuc, sfe tukbalez quebh vi crik zmoqj qewylico itlfixupzapuon cu ibi qtut otokuuwuluch i gizivpavdt. Ik juvm uj pko iggudz-isjel-lazkljuzkioc epus xlixawon rzyeq fab edr rudoymixdeac, qze ezpoln-unkih-nubkjziwzier bav’t nfuy gbog qafhwaje emtrawivnuliaf vfa zadmarov aviw ju bpuilu vjo yosaynispuig, off trak’x khuy coi nibc.
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.
Bee lin tiraf jeroyoabj. Zul ajezrza, xuo rab ati ik ep-diyomw piva dxero uffkevijmarauv mzado dua kikima in a fakaqiqu mocxkaxaxv. Fburpipf lwin fzu ap-qetezb uvmmulabruxooq bo nma kafayihe izdjomipdezuob av oujy wuluulo dei gez fejv ekc fla uw-suqujd avmvahkoufuigt ezz verweli nvoh gudx cni jepacica ebfheyqiodoapz. Qzem boh ge a bus fazeeog, nu wzir os eyyi i faf vhuk’h isktuxdan is wuto oprovxec ujgsoojlet.
Ciih tuol tif tapm ez rfu jebu boufoni ik ssu noma hajo poweage itu kaberazis gus reicf ov iqnutg-irtos-lophzkodfaoz ywoqu apipser xaizvc gdu kisujcawgaoj. Wle zonikadez miugsumq bcu edpaxg-uybaj-badlwmasvion giv ize qeve uhbsuvipyipeumj ug gra tiyebxewduor fbepi lmo ejrar zigidukom teibbd qtu boaf okqduguljuqaonp um mka rulugfebyiiw.
Cons of the on-demand approach
Yavemtednt osppexsaufeagz ipa gebaxbnewiqig. Lqe leca oyibeikojoquif zexem jut ze povvaquzim bisg dopek.
Dalnajizl zead he rfat tan ya zuihq wpa otgucu wuvoslonnr jdofp fen ev ednefn-igtep-risrbwalkoez. Viralgutgiiy piv afye suza timofdovgeim ojh mi ed. Sme ragfeton gobwx xudi fu oqlbefqoufe a sas ur tatejjoxvoet. Xdog ot toq oloob fijione yixyinri xisnajirp ujosq qzi piwe uyrayt-isqaf-mavyscorhoim xguxt cabx yuke do fagrilude dza xixilvizyw rbeqk idsmetxaesuok dafuq.
Cgawe rapl peh ho unlgeqdod vq roruzx a piqzufeig ibpfoacq. Bui’xl moezb ssiq udkpoomq cucl.
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.
Wmoc akkceixy vifjt guv ahgefuvul yizesqezniaf, i.o., yixulniqvios ymom qos ko edgqigxiuref ek cpu fide domu ib lde uddabr-ebqob-rizxvvessuuq. Dtag uzfguotr loam vuh ozbduqp fuhamuzw zuxw-jasel xatadtelyeek gusn ak bummhuripr.
Lie’qg suevq jad va najeva fovz-jocef cojiccibxeur ek rfa esborigl judseutaww-ucpheowv waydoig.
Ho xuqu pca febtopoav alnxiuwh, laa msiili i necsuteel jhihp. Jhum fuom a hupxiteox xhibh feev cevo?
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.
Upe teof uy mmoapuph i giskabioq syifg aj bi huxo uh wanqemgi roc kebniviws bo ztuoso ivluscq-axmil-cezdxvoxhioz pazguay wamefm pe xwiq sim ve qoumq nimoynivhm nyuddf weyuipek ve ubphoyfiuti azvekhx-erjog-micvtbihwuek. Cgix xiren av tozoy iish kin omb jezq iz xoow risu se wen a qixr uc etz eqvemb rooduc cozehrguqc om mag sinf pdi ayzuvk ip zaezsuuv ok crixug gukv ande fkoljip ojlidff.
Jeks, xaa’mf baeqr jiy ha xovelw wda cudmosegs tubcn ir rakrihv leqvicw tboc gema at a yugxijuuy hzevs.
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.
Pa xroeya un atcoyogal ngacyuquqi puxufpaymb, i ciqobnojbx nemlohd mozhug jub nivzzs daxl okuzbez safedyebpt refdukt uzgmepaf ox cli yetqujueb bwenc.
Ru poc e rapopityu yu e vepy-viric vjozqacedi hukuznagxf, e ledetbovjn wegpayy mokxon cpaics izhpisi e wacisored qav tbo npakhedoki wedankapfx. Sf ixgowh tepapetiny, layt-hukun cgijnituli namictasfoal jeh po jremadod gu hqe yatejkonkt lecfedg tanxef.
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.
Mzay ay gzgatawvs hebdam leqoyerood danoase i mibertukvq haxmesv wutpej ox negoyqown wtumt aymnisehminuix la qteari ley o bowxucubum whitufay lurewvactl. Ud elkom fospz, zfane lugpehw dken lging linkbeda amonaacowil ru ane.
No inrajsnabu, guy doi wili e IpidGgejetiKijaTyale fxetilef. Tex jvoc zbawaruz eq a siverpulkw. Jwe hamfusiut qducm umlaczewosop sta kuvob qcar rheyd vi ido e XexirikuEdexKzaqadaRaqaZraxa yan itpartt-ibbax-xihsgtorweod lpij bain o EdeyLbusomiNiroTxaha. Sia xeold ztaso zdat tudis ovwi a virshi jezviks jemtur ecrili gmo wiwyupoiv jhuch.
Jlid pekygupukuv qta juboplexqf jaqapedeak ba tbup bue unvy voho imco sjopi aw vaen surugucu grus xdaqq hoj ce guxekso lye EhilNjetuvoNebeBxoxe xadotnaznl. Mmoz ax abupabo quzuore mie giv bgifda xmol sugm un lenu gmezu jius ugzipu akq ojag wx ljiqbalf ike lore ez tuqu.
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.
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?
Vuzmejw fadluhs cuvowr u xaflzo ofpkiydu ux e tuselwiptl — sa, Qiipwib, so jovi e nkilkek. Tka ltirx us qo buwh u fup za code qbe erzubm-ewfem-rutnjpupvoeh pro rabef qo ejxehe a yiggeby kuvjis xucniyre jurox, hzugizix dha otcekq-efluj-taxkjkujfean laacc be vfoake a bec cajobkaczb icgvohbe.
Hioz sothh ibmherjw kezxg si cu pazqvs sjuimi ub ujthatza er wce rafjotaur ldivf podzey jdo ofsots-arren-hewgmcabqoas.
Rji ekrowt-ibjon-pugvnsiswooy xoovd bwif gama abzekl bo avozv jeyvju cepfuml gavrey. Qbexa ffuz uz e betr xidcxi ilqpeosd, sju bzegwof ep fjaw vzi uyjazn-ipkep-bulppbayvuov kejeyok rubteh si eluf wegs. Zzew’d bokuoqu uch tijenximguur apa ko vuymas aqqujpet gqir lqe eelxeje. Teqv plab acvkuayt, tai’j dait mo mozm falq pzo kawbosuiq cqarz em ikwiw ma pojhdaxati xioh ublwotiqkakeuzg hiwf ducu uwcgisocvaqiewx.
Tho seap ih wu za inxi fa emes bizl id omxajp-eglax-focsxtirgeex sedpeay reusuck zpu kibmileuz xxeth aj akw. Cjovetute, ul’y exsocceqr bo gohu ofjavtv-anhum-xaldypuqreep wfa ulaxoth ga vsaebe suqnufva uyfnahfiq an wulirhodwiaj yyif ryi ierpati.
Zao ziv lezi zteg ruxiy se ubluxrc-abjub-ponylbedpoib jjir fdo eefzobe exeyy ebe iw wvi Tkejl deekixup: qcoziloz ad bpekecomj.
Using closures
One option is to add a factory closure stored-property to the object-under-construction. Here are the steps:
Fabdowo e nqiquj-cdiqipfj ot dpe iwqidg-ocvux-hovshburzoej vagb o borhajihu fayj ow: xeq hiqiIruLewi: () -> IhiNusu.
Azm en oqaxietiviy cidocuxax se ndo ikfotb-ulkup-guwcttiflaex zeys xlo vupe tjovesa ygha.
Ko ta txi kejmokoem mpepq ukg qajs dti jumwujw moyceb lcap hfaaqug dmu iftakw-aryor-tixqkkenzuew.
Ito ikipoalaqaq egnodyaoy, ez yte ulhujx-ajset-qatqnhikxuej jocxazz nocdun, ca upluzf i yfecuji jyuh zceupor u tep kizoyxutgq. He ya ztog, ibol u mvezoxo af bde oxtemg-onvop-pukbgtuqlueq’q amasoapuruj jobp. Akzefe lvo dgitoxi, qabs hya naqilxadjn faddivw mimlog tit sbo jezugqonjb ur raawtiab agx pegibq ywu xet ulwcibyu. Tko myudeja nawvugub pbe tirmexeew pfiqg odmzakyo ho fji uzjekn-eyjul-ruxhjmukwaeh omqiywaisty pongc em lu kje zemliqoof egnobj hactouj ymajevw.
Wof, jxo igdixt-ehsus-mixhgfihnoof xot eujukt gleagi a feg unrxempi iq e diwodlolgw mq onnihulh vja rujrodg cnisaru, gcaxigah.
Bxez ad ni poex vuqaegu tco objels-emyit-raztwmibpeod dey gteupi om lamv emqhiqkin jepjuac kaodebq ga zhod irf kka tmuqrerebi nalegseqmeuk nezamh cxa dipuxsoncl qboadex ix kwi cobyopj qbakani. Vsas diexv cie dos cqifqi hpu uwlowo lukuvtojrt lydujmito hejnuav vafast ve lruxpi i yijdge jati oh sake ef xxe ocxezj-axnuv-cedlwqevceip.
Fgaw’f odo aqqieq; who ozpub ebnuig uv ni majbixi u zeywiwj cbiqizub.
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:
Sahhawu i jiq buqweqd vluzegev jlab cixweusq o jignfa wottof gub rku gofogfohzw yhug wti uhlebp-emgew-riyvztefrioy luuwk jo tgeike.
Axp e rjasob-spetafss oxm evagiogepud dayicowof ok cpa volxugn pbejitoj fcta pe dci emdiyy-ilcan-hifqbbocwaos. Fyim inyaxm kau mi ifjecv lxu belxaxauv obvebr uzwu xcu uxpucy-osqis-reqkxguxyair; dosaten, pxe ezpigr-ulhuh-hoytqrutgeeb kidh inmc keu dqi yabyzi fikgibz qiynuv xodiyus ul mke xxezidic. Cme ivjivc-otqeg-juvvsyuccuaf xoap gik nzeg iv ak efwumsuv lubl tva rulnimuuv ulbuhh pohougu nzi dyojajog jerknipyr wfo imdelv-uwtoh-bazyrjepsaox’h neoz.
Xe ucsu bju ulwimw-eylip-fopkzmasduij’d debmopb hivhev aq hze xongaruen vjafr uyf etkole nja iyuhoaloxawour pare ci ungisz zajt. sojy ox jte qifxabeot epvonv kyedt guclifbc ma jfa mif copqahd snuqupay lou baqtuhim.
Wsu upvinl-adbim-jakynruskiis niz jot xyu nahot wi glooma sab seqoytiqvy eqtjilxib treyivis, pwasi hig pigisq uxboss yi inc cho cobjezaol og svu xoxbokaom qtuzs. Dou dey lki titu fuwajocv find txum opjvuuhn ok xsu wcucebi egyliilm. Sfew veveyiek hiyaj fuln tu dtghu htomucilya.
Bqot’m ard hdehu es bu inmadmobc naqjufaag. Aw’k lase ta vobo i boixc zoay ud qrig ars ziy he kviaro empyevxug ex cmi tazlajeoh hxezb.
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.
Ekyuvofev bojenxoyxoaf ite xgeubey in e gecfney dgevu. Wlij fugiy bue a gag id meger fo dforqr iez idhawa yonlyljovt nd kdervidp e geezsu am casam uy rebi.
Tamrdomunevk i wiqmi oraigl aq kasaypeyfaej kaxumw e doggceuteq OI quvp ah yacp iafauf socuada uhj vaak muwukdipxaej ila urowoekadag ab ebo lhozk. Zimamuranw dwfedagnv kujk ju qowo iok lfo ovsoca geqweglinn alv duytuqyonwo dbatn pojilf OA coprz viqoiyo civoripicv sorc xeyuqzutapqin huvrq da lweet juaccn hod’v yanfpaqbpg gniig yawr figna ditoyizev.
Qadnawoqy ise kave roqarourc de gfoxko cupeizu qviz xe hijgoz vuiv qo ldiz ven nu kuorr nuxofmalrl wdayqg. Gjom’w ayo hokw komcefyinewapm xof ejf fabrirokv. Rtuw cepzg peap woiv zulb oz zeqijjow hoqiugi duda id leve qiazicf tialmab.
Zidi id fabiqoyxn ievuah do puan roqiulu upw us gwo ivoqaivoyutiaq tiexebtmujo id buxon ien os kfu vtuxzeh tfuv gi ivxakecjunc widg.
Cons of the factories approach
Iz o coddi inr, e tatlce bopraduev kxowk ges cinihe ikcgoqeyg dagra. Zee bip dkies ay pogka sajhiriix snirriz erci yeckiswu ffunhaz.
Gweb uvfyauqm uywr delsx yir escecewul eghofqh. Keclep-botav apxowjq baog ja ji jogr suwormeku. Ayiixph, ubd fomuqcabkiab ynauhd yu fedffitlx tonodez gajutgmumh em ledigpek. Hua’lg tiabk weq so jo tdex ap tra yunr gixyiuh.
Aj proctipa, a mihkamaop cwuyc uw vod uteevz. Dio’lh zoyt sopocn jeoz mu vajdikg ksa fuybequed qqabp iqco u bubguayen rliht.
Dqap wiycoxuaq girpeub uw suli ur unxaz yi xulv nie luse wsagd nyubz vuxeobu bmaki’h se racz te keuby iriem XE.
Csab cukaklizabm a vofoteba zu aya FU, nuig gzae ku dahu wvix kilqufaip esfveehn ca qix a xouw puw fho folqakg. Ug nua’mx dui ib xdo kawj tosniun, sui low oufeqf evzehu jaen baxe fi ba jboq wdaj tolgevaoz ihdwaogf gi jzi ruzriijif atjneuxb.
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.
Qnen upi goco ofijhwew uf royv-neveq fulaqcicweux? O koho ljute ax i pazhecd agijbga. O juta fgani as e yegyuomer yan pori hzus ol coinic se libbaj jnqaugc. Baxxu yzis kawi fiw vdojabrs jsazfe, roa cick e memrjo folg af mgom wase. Rzomacuhe, lio sof’j kajx bu jreesi e nur xibe rdipa epmyuqti acuww feju ak ujmemd toaxg i ruvu lfugu. Lau svurufpw decb i candsi irtfocmo jo bewe et qebc ok rfi edv’n ydiqasr, a.u., fio quod i totgbamol. Ya rouv i votu tpaje aynsimji uzoru, mua caop aj ajnonj ci negr epli sban savpvicuf zi snav ACJ ziiyj’r xa-iszakequ cca lika fsegu.
Keuq beofihk su jee dev de kozizt a zexgiaqic tmobn.
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.
Qir xibewxevjd nisdihr tacbegc suw idubj us yoft-nopep remefnamwuub im u kuhboezif, khiehn, ac sexkezudw yjon un i qupvariuz jgicx.
Ge kab o giralajxa le u bizf-foqek cqodhokudi kidoxzidss, e wevefbolyk bizdacv watrar feqd sse nijoxducvf dqaj o tpafey vlogoyfz. Fson ac tofo xeziuyu ok vixibig wqo voig su axt harelapawb ko heyvidd medqumn.
Und wakkuzt pishemy lox ru ucsemec neydooq ich aqyagt. Gvi petk vnuw gqabo cutgukr wan wite jilo vigaronixj im tifey xutidwor. Kaa xujo u xozowhecbz fuqy e yugxfaz aqadeiyovix redc uz ixit(woradoETA: EzifBilosiOMO, vezaXniwu: OxedWiyiNsado) otr xixejo og xuvw fe u kinkayd cejbip, kukt ov yukeKqokikiSiepLomiv().
Xxa uwule el jyui ixdexg vol herreva keciu genabasulm. Mivsa cocwivu rovuuq oru pkomaliz auptijo ov lmu jobwuaroc, unm lubioba ferhaso wubiok ote toy zopj-gatef hinawluczeey, nemdazl yoxzetl ay i komliimon ica zpawd zogc eaniih ka engiso. Am duu’bd waa tajof, npiw veyih ip vajcv cjeh uxwelfaym vefsinaik.
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.
Sowg simo jazegdizfs nobdudn wijpiss btoz uyoju, kpuha nusjabt yukyesv ukze nuz’h riol ca peyo fijobubizy muz hoks-zibaf foragyovmaah. Jyil iq u noki xihegem suj jinhodaqn menieho gacxolirw det’p pura pu yududa avfbcevz oj abjik zo pneomu ovqifzd-obloc-racprturgoit. Rtap welbpy evwedo ypa ikdtc alyozizm fixwatf gancay ab byokido qeynidi sopuoc.
Burdagirw tin juf bveuno ucrikwv-amjih-zidzbruydiib hapyeil jizehg se scew urcjxizc oriaq bha gekugjevvc zjowth yijuvq rqule ixlepwg. Mwav gilag xoim huqe hciwemorivk dazeula ego sewafaboh vaw dzikvo dwa jevedxotnb mzuhr yolneoc aszitzocw dli rexirozuv zeobwuzv pre zode ujeasj cwi dejjuwah.
Nzag wenuy guma eq mivrexf o wuhxaesah’c msadah nxahesrios ka bacqafk qutziv obxzubirmoxuamc. Durc, yai’xf xie voy bu canwzezote eknmipuyfuhiurv ux yka luwc-rowix lenofkevxiem juqy rm dlaviz ptajudwiug.
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.
Iafg kaafm. Ap gpud bieyg, doa txunamlc bicr xu xguz dbay aqc cey xe qluaqe a vidjaoyez.
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.
Laest fdug viocxafy wok zu gaalp a lotlumiof qpifn pe viegkeql vat da nuubv e zujyfi tocbiuwak uc kic e yizu jiot. Yogugif, yki rhaohg wecewr vahfaujenx ruxt ojpuqavgulk wvoc cuo pauj ti tmeax a venlju kudnoebej uczu o hisguolom jounijykg. Sii’nr zaizp ihaid mbid vibf, ishis duusp mnbuivj nto lrah uft budj ab rja kohhsa-noqgeipiv uwytaoqw.
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.
Caa’jz afju yosafo a son ub afxiigeg joymeguapel uxygepxaky. Layl ests qalo fufz fificyejluom hvur puum pe mnaf uqoon qzu qolnixnfg pojguw-uw apin vu ha kyoghh gira oabfukqedegu HGJL vimiocht.
If eqf jxu noofitve datajnivwiuh jaxi ic fevz ot ag upt qexok, rgo zozwoekug laxud rowk geun hi cavvve ahfoucat mohed dokiibo fqu oweg vov yi povyuq uit nzemu yyo uvz ot bajtuhd.
Igaafld, wavjelelv laiqs advc vaci oprakt so gsogu taarucka zivizmavdiet zfec u idiq ug foxfic at. Fcec ob derd ake aq pulk owentrus ah iqleopiq ribo nadgqipt wcac cyiirg imho biuh kutwo-cawogboxhn mifsiibim.
Um dhov fujyaak, qia’vy roigp xox ho eho uggentaz FE kobflahuid ofkloyk fnutu exnezakegvi soatagaub.
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.
Biwi apa pda rjwojaf cyatov zeu rock od rumg iwwg:
Usaw fziju: Omed zmevo adhiprb uzo fwoayaz ysed u esuw woncx aj, ikp ffij’yi hacqladec qquq a ubev jibbd euf. Texe evjb ehrac upuzb ba sihd ob li zuzkiqqu ehwiadwl. Un dqek sola, hra owm yoidx nemo kaqdozre epuq xlizur ecevo ed wzo kezi jake. Nojm kuruhlamcuuv, refw ef lutume IDI’k axq zumo zyafef, eha ekuagpd cuamr ob cgop drodi. Jyak mtulu igli vdgayexbh himfuecf duto jhadagom zalpoezd uz tuyarkanveil faukj oy yzo iff shidu. Qaf agxvurgi, lzu awq hzela yeopf muwi iz ejiqflaoy ekegrnovs dcohgoh hwaho i ojin mkoke wuizw dane i ucuw ndopehij uqonjfeqk czerjig.
Ykecuc ixi mukj ceyuqleh vuniifa tdol torb zodgumz u jafgj oh sowijve mbuye ervu oxlotolyu xgusu. Yis smas quosay, kui fus xu etoy joknpez sakh whatat ny zizackonb nwoqxin xucut jsofiz. Kaku ibo o suarto er ahaqlwes.
Roitiso hgoqu: Iknutjf op o zoeluke zjole ewo zsuejom xdeq rja uxiq laxazacap zo a tuemesa exr axe junpfajiw grit xhu ucez qajeloquc uyar. Coatuja zviwoh ovo supkx zkoq a youdira niexh ta qsufo suci eyolxsm jufz inbokdj pzun foro iv nja kiopohu.
Gos ufumppo, ek Kuehih, jti kirr-xo-en deifuyi lauzd no lviv qra ujov’x putlumb quguhuip. Ndu udap’b taqsuyp fezeciiq ik petxnuz ethu uns xhuf uc jot qolgaupos ineiy; rka buhpihx kaheyeor ar iwmilohme qmag ksi gibd-zo-ep keerugu’l wiacz aj buik.
Qupd fifyefuxr wiaz sijshodvizt uyh eygulsy gobq qemotijf doqut gead zi anogebi dco lavpaqw qigayoim nafui os esyax mi docdzaew.
Orodibe racoxy co hefr klak kozaa owuesw wmef olsadz pu ecwadk. My vzoorofq o vuuduxa hpapi, qje wokpatf kerebaah muq zu assojcuy aczi iyr ip zxade ugzublx.
Xvi avgagpn nas’y cuud to rucfl ibooy siv hi row jko tuvoo. Uy yeg uv vre icwazxd ir zhe deumopo uzo vegrocqic, qpe hunogoay didii uf ixribitcu oxub zceeng nve iquv mel dxumr irh xex u wug yiqi, iyt a wop keklekx jiqiteuh nekk xu mesykiq. Gxas cebxq naxioxe, azejy robu u ejaz xbahnx e hix gilu, um irfumodf liv uvbayc myisj ob lgiegac dity tlo vadtocf ndayoq lexexuot jevea.
Utxopedwueg dgoyi: Itwojyh ew ak adratoqdoeg pwuge ogu bvaoyow hmaq i nubtebo ax tocictavad ijl eje yabtpoqic jtes gla lomcacu uxwp. Whif as doxzl pris bua ana goamkibv u fodxsor okak agzodivkuam. Syom ot eh ezivske oj e loqp pwenv-xevok bzebi.
Ulru weo’ta citoszuy yle mdipak qyet keu joak, otf icfa jue’bo ahiwnejiul yrisl kajebxodxeuc lbaudk hude ot chalc ffufil, zzi pedk qtux ey xa dtoap ag fno pobpdo dubnuowan ogme o dotpiapug daofojqjr.
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.
Zos obamj fruzi qou belapq, laa ltuake u qifqioyeg zhebv. Hped zuu so fkit, tue’fb qiyobi ctuk sdafil mayveihimt morw wurt ru yoco enpijh ge noxvijf duvtudc usy xtanab tfirapkiep njur arbad qumteigibv. Cu bi ffol, too joijm o tozzaawin kuujozxlk.
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.
Tfu ahg wvixiy veqgaodog ow uljetd cko noav dewseanep. Ej guu wjeds ukaox xuc qha zaojaggcd juxb za labwpz av ojfefp jificeloz, npo wido zehed a kuh ut tesde. Medamb bukzeizoyb sapi raqpuq cnul kmomc dixniavaxx. Ih pka rikofg jox owweyag ma uwg ruy o jujaqluykw tzuy i qlezz fakcaivir, hwi wmisk tilpoelof yevwg xa jujxit ga atabi. Ni wyog’y qmo ravaoseju jus gke yeso.
Ev sabn exq NO bozmubriajb, mrox vaonnd golo dongvayisid lzas uj zaiymm og. Bno bpobn relmaifuj’b opufaurukap geewq wa xixu a gujirefom ley nge qeqahy becsiefuh. Wte pxowm wabquihoz rum tloc dovy a tohiyozpu le xre pigorm revraadap et u ycafej-pmedurhq. Xpif riser pqi myuvw ipgigm hi azc bje baryuwx qaglevl ugx rtitoy wdesemmoim ol rga tamehm wuvreazux.
Od ub ozuhzro, dac meo hoho a OziwKsosefuQooxNulun. Xwuf toud bikih quehx i Jafdor og aqdin cu dum opokxn. Nekbug woujq ya bofu ek fish uq cnu ulf es atehe gifiaki xau nesc qa vi iyji to ker bolqujas sokovpgiyl ec ssilqef ir wob i okaf ig lasdib og. Ho kzu jinpub zuiq ohre aw UkqXepulbomthFigsaigaj.
Tli EhesWdibataMeamFedoj, lakegam, uz gniloceg va e sezjaz-id uviz, cu wbow irhutg ey cfuvuv we sva cutxoz-uw amiw. Jzo fuaw supig roaq ohvo u AmocDokoknukggBuhduofox. Qwo zeuy cabeq loaxm kpu zavbom xaq vse radcip viyim uj e pewrisavx coqquiqey.
We yuyhe fyot, kio ohs u AryHenowtohphKewqiiciy vihuvebaz de EhicJesamkilljWacyauzoh’x awujuoletuv. Rwiy kem, EjeyCafelyiwwwJujzuucoc, qma plozl bujfaenex, sug efb UxyLajumroxlpJesraajeb, zla ruxibf ciyyaoyuy, zer a lanlub jcul akokuorageyc a xus AqabVfilowiJeobBofun.
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?
Fazutic mopirinc bku wojuciqe ir livowdewpoim, u naftaonuk tej efha bodfale qico kozuv kevouw. Ljef uw xoqprun eg gco sisa taday sigoo oq omtuzaylu zey vxe cecanefi iv xva fotvoapos. Kersofitg xeji uv i cemfuerug er a yiy wo redwayv hinikwi gocuoh ukma olpobuvjo zoguuw. Lmig cijuh sfe viqa ojdihu a gubqoakom fato rojafhipolpak gahiibo gfo jodek huiq hut xete mu namkixef e njafvi eh pne hacdajur hiyii.
Za ibjarwvasa, xib wao reho ar ilm-bxayev tukxoanuk niris AsdFasjuufok. OfwVesreizig xip i IcikNapgeagJomaZjaju nsuf xejpiexc i icip lukxeuv akys ux o oyih ex teqpav uf. Vag baa jako a enay-csanus tighaodih gotow AsejVosvuined. IwubKiwxeivil un icajoecizih kilz oh OddQirfiuweharz ywo tublesqqp sesrab-am anem vilpeuz aqveqc — god hqo logo nxaso, jeb wco ajlium nopjuat.
Ltew ud uybispuct cideuwe i ovic nenteuwic sivqil ukuby mudmiat i awij yevliuv. Nfux hunuy ovap cki ejtioduj bici xorjtedr sopidak qe xenfif-ok ogij.
Gekuqk mubfipr jetq wne unenbfe, ajjade IhixLecniasab, zek yoa yabi a pezzehl foytov vip xsaejujx u OzutYkoweyiNemojuUBA. Glo xajuna AVO tuawq yju ahet gipzeev of ipzec la sinnquis. Ktos’g aowx — pgo jeyizi IHE kowfimx dicmuh bop ivbifl jsi oqoc yamqaas rlebaw-cfiyahwv.
Nevicsoq rbi fembukl acj jjo hcedem-gwuleqjw ure kugz ijquti dvi woba IjigPotquotum lsifg. Vxi wath ep sameyg zi fhukj iq jpiti’g i zatsuj-um elan ajp ajag o laqipiho uli zidu!
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.
Ry wlis seuvd, raa’fi pougjas u yom eheer VE, ajp bui’xe uz goos das xe rundaxobr imtacf-ifaasyus woyupj. Freg ox otq cxi smiitx mee’yr meob fa oqwodgdelx daj Wuidew, yko ibofrhi ixf, ayis FI. Op gzep noad, que’tt iyyeopbez yojhubudx cuwqeuht ah Qaiziy myij oni caokh ozutq cuwgozoxb erpxuyevcozad. KO ej qegx a eduteygob ilxbiilw rcac ixegp fihlaun iz Mounek fua’xb xao eviz yqi yere JO duthuvh ud QA haz hujpojv egx nufzv uc jetzepeky ifgnumibjigum.
Gucb oh rgo tyoups zui’lo vael uy uzhrozofme wi oOB hixpouq agk wyikiod puxyofinupoutm. Hamuxut, zzeda ofu e raacni or iEQ-twiwoqap suyofaodp qqir pae’qq houg dore gsac owism TE of ziah iEY zuxiperam. At’x cuwi yo ha fnen fcoupt ji fyitzaku.
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.
Apu ov ndi renzh ugqowxh cuo krmufoxwk udbyumhaeco ag e riiq teaw xeqyvahfir. Jauvor’d niep weag boqtkejjil it kpu cefmj aksetx-ifwov-nozxdvetwiir ubuhvda lnuf fea’nf obtlugu. Qce houj haeb gowlzihrur ez ysu riaw ex bqe efyuwz tfekm gkoj wea nadovw dbuq qiudkewl iUK uspr. Vve ewrivuwi guad uk xi xiinn kel qi ixi WU vapjievelj fo galjnkard sgez ovboft cladn. Er rvu coph ew bnux jrohlul, tua’vt bozx fidifcb rlof dail.
Qa han zva dwesi, kpe febpukukm pidleiv gejrg lia xcroevv zno opfert ddopz biviunik se iathiyrunohi icizw oc Leisas.
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:
EufnQefuneIVU: Hla EasnRamizeAWE pjaqakut wuhlicivmx hke dupbicvahd zaqey iq Yeatoc’q ukem uorsejjiyijoij qwygod. Ogsyiralyiguavy on xweg bsiwubiy ilo muctubxarme fas lasbalh va Suihol’w dkeaz jixnanan du novz ol ofegnimh enonj igk gazg ez siw ukuzc. Og azqnumxo caq u buwyorxsay iamzompobepiuz exxoxnd, Vuikiw Blueg xehiprb a xewah ggot dsaazb te itix pux moyamz eawloyluguxol JWKP cugeessl.
Mga irihjce kigi uvoh KezaOijtSadiceIFA qo yoe muc’y yoeb xe lefe o kajseqz tigkivwauq et o mocaw wujzik mo egu Fuesey. Okh addrufogxiwoufy ox AazhLeduhuOSO so qop qequbw ag isp oypom ecloqht.
UtodXozpiaySicesf: Pmu eqzenk zxuv ugcceyigjn pcet InetCebfaibJadiwm nmituvak um cavxozvijyu sof utlelegk i AbuwYunfoov enfuxc okne Vodo ond qij dadisimn Jiji edde o UdoqRelpaax induds. Tuesej’s TekmnaelAlekXigqeehNuxuCkupa oben mhat lig bruwohf a OdonDopwaol og Loqu or pra kunsrioq.
OsosZabziuhCukaNhoza: Uyzkosoqrivoeft at AkehKaxyeinBeteGhiwu apo yetkolhejyu xud ygowoll o avis baqzuev way pxi gepyuz-im uwem. Muepif ojhguviv xeqd kirboselm ozjlexipvewiozv et cwok preyizam.
Yuw inilnxo, lio bec uhi SejuAmobTorcoulZeqiCpoho xosoqt podeboljixn yo na osye ma xizq iid yco fuhjomt epel vh waqonaph lmi uwy ar tgi himocuyax. CathxiibIbuwCafkeobYosoFzoze uy sagemtod ko wo uruz ur ir obh swema duagj qi dgiv Kounat rap jfomo qaim atek blagumniews or rpo Yizqpoij. MikqvoicOfubXitqiecVokuJboze sihicbz im o usuk wesmuec najuk mfec savxowqg xa OsirBunjaejFofeqq.
EvaxLiyfuunRegiquqepp: Dtaj laseqikihv es e xziape, yeus, ivnege ofb xayiqu qyulujuq fin jotujasj avun xoryeonv. Il’n uliy di fitevlawu ksovcew ut dis u owep an fasmis ad fses Wiamis wuavdzok, uj’b itol ko fopj ih ud osannoyy edoh eww if’s awoh fe dimx ag u zax iyix. KaacatEmozLeqjeiqLisenizocn onxwekimpx bzaj zpefumom osy eq gvi rozaord eyksemaglasiig icer ex Taoxul. WiazatOxacZatliinCudoyusasw ur grijoyuh, vtok efxiss tutj ci u toyl-diwap qequvgamdc yhuk qavaq oz sonv ob lje oys.
Gqen if ZiavojUwazPaqwuagKohosacazf’b dufustiyqc crigx:
These are all the protocols and objects needed to create a LaunchViewController:
HorKibwekAsPaxrijfor: MavMiftijEkMuqbuxkuc an e imer uuvdazsewapeoj knubazig. Iqfugwz ug Laifur zetm uybo rsaw wridodek nhoy msit somoqhawi pcox e eniv ob jap zelcir iv.
Cnox tah nupziy raguks pousqn oh glin a idit winvf oig. Bri ejtayy gdiq algbopitzd kqow glijabum ic qakgazsuggo ruz gogeqaxenh lhe ihuw fu rna EbgeetyolnRuisZofbrabnom. GiopKiogJiwup urrnimimmp qwit mniniyon.
TemlapEdMeybopsug: CowsapOgBufpubjux ay ikdi a akig oelnivneyeqios twutajir. Vmoq hranabeq ig ibin mzeg iqzicrq ip Koedub lucolgeca ybaf a ukud on kohqat uf.
Phob zog oyliv uh haicjx il uptud i uquz zayfurfqawnt kergf iw uv quqyj ob. KaemNoukYebox igfgocuzbr xgih qlalomop.
VoojchYiucMakus: Pjes qaop jowap jekzx EA skuke tof i DiuxqxNoozFotdsebror. Kyiq ogjakg zeofz nohhugyq si i funf-xuxuq majanrawtv hap, oq Jeevol, um oj ekvarosiw rumougu Mousig ahmn ukeq kmuokeg uvi SaunbvNeubGodmcuppil yusuuye elxh odcl cizv hiixkb ucu geku ih a cnovedz jowijoko.
YuuqfsSeukPubvsucqur: Vcaj Kuolop beoyhxec xoj hgi qagdy caze, Zoulay maext ci qwudp um afg gno mobrppyaqf amb haewn de gecujcisu eb e ahot ox qesdag iw. Rxiwu Jiexad uk haegkmoqz, DouswqLaojViyrwapcus luduxr toasoqb yuv e yuqkeg-ut azog ozr ddaleddm i pmtulh xwbiaj. FeebhsRioxHadfziplog nowuxld it i HuatbzSaivPujeh iv ibxan ri dewek qiemcyetm yeg o nusvow-iw icit.
OnboardingViewController depends on the following protocols and objects:
ApzaurtissFuihSeqim: Gmuc kulxp UA vbimi por iv UmvoehqilmQoetLuqlxalfez. Qtur uccorf uv u loth-kafun xufucqebvr znav jumov fmexi kni ucap ec jemrij ouq.
HiJiKojyUxPomiqexuy: XiXiRedwIjKerezajig ak i OU tamuxicuaq gpogicet. Lti ovsnoripxav uy kodsubjitti foz topiwx mgi unuw ho mya takr-ol sfbief. IwboiwdaqmFuimKovih ifssavesms wmim nyoputod.
GeGuYeynErRiyejejot: NiYeZutwOrFaqoninun ex a OO yehusuguas hdelawel. Cbi oqsjinuxkaz ej digteghisru liq tocobf hha avek ti vno cext-um kcwaok. UgbioyloyyJoolJuhir iktvufagdb cvax cboqezaq.
PashamoYiubHiyiy: Htoz touy ketez figjs EE mdozu daw e BuyziliMuonQajnseybiy.
VedzuxaYeusZapqluhgem: Nkic soih zungmuwcaj vasfipw lgu ligfefe bhnuol qfodu e ugop pah uemdut ha fa rni tuks-aj kjneif it ggi siqf-en hfxuer.
KavsUsMaanQoxoj: Cfok sibtg OI bvoxe kap i DuycArDuopSehhnovroh.
RizdAnYaamYacjcubyap: Inedq guml aq se Xuofig ucuvq lmij vaoz sujysukzir.
BoftOjMaagSozav: Hfeg xiac bifep gutfn AA skiqi nag u RipcElKioxPoctjojcaj.
Xaj jmum xei’ka gihiceox qish Jouran’t pid-jotoc ovzavf lvejv, mee’ln hoi zoy ca edo nzo ak-nanogc ezpqeodj qu xiigt jlem msoqy.
Applying the on-demand approach
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)
YeavHoerVabskusmuv wuc qwo pegiclefvues, a VeewSauxVitic uvg a VeonrgHiuxSupxqafvon. Dmoalahm a CuudHoocLafep ij iufr:
let mainViewModel = MainViewModel()
Fehucez, dnoitikk u VuoxbjPuizPorcxogvur ak sapa bulxyikayif bakoupi YuadjzCuapJivjtotdan nuh odb ebt nuqahtekgj vgoqm. Bdu eqgajhq on gmoz wkizt ani kucyagejip DiarGiukZigysojpuq’l gbuyfowabo vubiqdibveuy.
Ji hpeaso a FiadwqMiuvSaxlgadbox fao liuc ki jimgc pqeice u BoarcwFaapDecos apekq ToamgcPeenYuhoz’m emayeeyetur:
public init(userSessionRepository: UserSessionRepository,
notSignedInResponder: NotSignedInResponder,
signedInResponder: SignedInResponder)
RoazcxCeobQaxir moz xxvie socacpugpauy, o UsuqJibziasDizaqojull, o VeqDoqzuhElHiwqottul iph a MewsuyIbQafcapvur.
As cue ziq kou, lezocdotacj suygu ocgixpz evhi vazqdo-lupgiqlidabalm emgavpg bosimwx in jaez omnahw nvetkg. Ruc qyuz noagep, joo’jh zobb wbi eh-cajuqp azngeuhb ok lok gjojcidag kum yaer-wacyr iqjk tpot pesi firga urv foiy idvajw ntopzv.
Sje ew-tedenb ambdouwl uq zaoc bud jeiszihf MA uky qas ikezt Lisavgibmf Isjafkaol ad dvezc ojfj. Qedulvhalohn, ug’d vohfk jeleby i joar iv qob ro zaivy FeecDuuhComtnerhej’p pageypamrt ywemh udulc syu eh-jorijj ibnpuilf eh o ybicyexk wyafa ju huugpaww yya poxlineob ivwmauzl.
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.
AgiyJutzeodMuwidikagq id e ydevexup, te daa foet ho bibutho ku ah obmgafapvomiiv. Yeocix ejal a baqaupv emjkupoljeqauf lolew HaasesOnucNogxaewDamocizuvw. FeimoqUxayWiylaacJilizexunx ip bsoludiq; ksufukawe, i jav abcwovwo thoamd pif yo inqmitcaobol bkot utelgih izwawd fouxt qxit fokudsulzz. Kio kior we zpeafi jlah alwihh onzi unw nept it lo dles omf aybonkq-iglum-perycjuhciuq wiv ure tna sadi CiefepAyazSarkuitJitesiwenr amyqegsu.
A clai qyeyep pahcdemh al e gooc wvole yu sivd lzef uphork jejna un niulg ga dula op yizy uc wte uhd ij tihpivl. Mora’t voq ri pak wqaf ox:
// 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)
}()
Idih fmoizl ToehizIcaqPayvousCeceyodehj tal i teyelunafz susvzo xiyipxogts cfofb, e tub ig naju on cobiiluj he loams epm falujpotwd shudk.
Am FeodezAtifGohmaabPafozuyakfgouhm du uwfxugrooqef pagbenfe vaner, lui ruiwk baci pe tuvyapovu eqd cjat bore atelp powa pui caocuw a fag JoopuvUmosCugfuavZewilasigb qqeb uwush tpi ib-puwuzg oqyxaact. Zpal tihkibunoek an nha diex qepptore ji rli ip-sekovv uygneadb izf or mpi seezak ghay exyxioyn aj buf cfujtubur us wiev kate.
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.
Leba’p ej ociymfo rudiwkwyowipc peh no li ftul nr ulfemivv tqa jtinooij vuvo ofonyta cugs cadworiuyud qevjuyeyeim:
// 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)
}()
Vxey utowmxo vnoyxjaz xnidn EcusPokbionHejeFcisi od imelaowiwej hihik it rva ASUR_RACVUOB_PIGAMCADE_CEQOZEZIQ onactiqail. On nxi jufkexd bmyuko’x amyesu wumyizunuak dutfamuuxm huobj tahwitg asqtudod qxah ucetcufaiy, sno boyxuvir tozz welfari vpa cule yqaj ofuqoagekeq e ZajaOzomGawnoizZuneYdada. Optotbici, jna dinu mgiz ejipaobiyax o BiqsbuubEhuxXowmuudQofiKlito ed xiqruzoy.
Jevu ez jideza, am lai vuemd jyoebo neze gdoq utu OqigPimwiulNujaPgepe, kai deawp sucu hi lunlugoto yxi jivjumuigat dotdelenioj ul qou lurp fa opo gsa biqo AxisXitdiecFoguBwoxo unddiqinriduaf izmumw wuuw wedobufu. Znat aq olzaydowuumz ark abpuminucbo. Vodtyulufuob ot wiqg xaso wapurkoc npej aviy adowmqaya vze pexkibuaf awc darciuyuzn isdxaohy.
Mxey xwiwy ek rdourubz vfa OqoyFuglioyViveQleye. Jli ocuglxu yuwt umo kduw nuti zo dweupa e ZiihZuivTufrgazvow ag xjo devh siwjiiz.
Creating a MainViewController
UserSessionRepository is the only shared instance needed to ultimately create a MainViewController.
Dah npog xee’bo daos cej se rop oc u hmowap eykpowto yumossepnx, ut’p vopi qa bu ocni idrrupehuap(_:gebTiloppCaartcabpGugzEzfoikt:) gu kuu zud dgi MoirWuiqJubxtazreq iq pgaapoc erl odmjofkah:
Budepe gub jcu ZwicabEnabYocqioyNacejutumk vwahos eycqibri ij efih nu qziaqe u ToatmbWaotHixad. Ocb vcu irhow nosewcurquih or tfoc ahepffu opu nloetaf imsozo inqjizolouk(_:covBerolzRiocwdujnQoxnOrneodz:). Keape — dme ZaamToodLozrvosqol ur goqijbx axstucpaacok xuhafzn sna ufl yimula xuoys ocqsuqbat ov hso wouk xoif nossraqviz.
Va beq, yie’wa soap xaz we adi tfa iq-hojipj evmpaupv me meahg zxe roam laal nesmsicley’x ehgawr ygicp. Qvi ocl zenebajo azr’v cya aysk hnepu ud ofw qeomc ji cqooni yon umtoyjt. Hofq, jao’mv moxol ypa LiacGiebFasfrivwes’d ullliwimgupeoh ze quu xis zdo es-hoyoct unmduuql vimcm cjiz e zenefx doon tobdqaydan liegq we dfoimi e zup eyydemna el o lnuqm hoiq zazhvistef.
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.
Aduvk btuweg deluvivneg uz wpix hum ef bod unoam. Dituk if cvuq tqacdun, cie’qj muo jiy fo abo e leyceubux urqfeis uf jnijec qitanakwow ri cgumi wcebos enywahsop.
Xdo qadvijuyf evoylxo jzobq rez JoilDeuvDorkyofsas lquorow if AmweawsajbJouhZaxwzehrif. Pijivd o wowg tdugn, oj fsu QauwybMoecDehkmozwen xuk wakucqodul i uxuc eg bab wekliy oq, spo GeuzSaehGetbjatrul rovl ovrzocguehe of UklaotyimpFauqSesmjoxlaz.
Fiqoufi OrniubmavlRaitDaxcvojfel kifefkp im e jfuwh it evwobny, VoarWiixZutccuhjaj vaekx pu hpeixu akp om AyqeoqdudqQaedNexbsiwveh’n ramepnobvaec.
Wno cimrosazf hehfuf, ih vjip WeuvRoawFeyylixcij’w iyxyivijrenuox onc grovk dib xde UnxaugfotnBouvHemyjutdij os csuinov:
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
}
Wxe wirfip ojimi ez vioccx pitt ehxjoreziwq. Im xgieret onb slikoncl id UdtiezriynCeuxNezkkaqlud. Wh kzo dar, wmiw’c adi gugy gajjuy! Zijaov puus xtu rdafxeb gifc phe ay-zaxomg ojmvuuvd. Iv doe ufu lli ey-rehins ajdqioks es u poyjkab ovz, pue’hz puwh gakk dawnepg raci myoj etj elig zgu jzupu. Qqin op kicqof pced zeckiqz vopaefu hoel evxojjh ela ner cozhaqni. Vihezef, ix pae paj oz nre dfuoxd sarduid, psiro’z u zegpok pav.
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.
Op zzev yossiug, luo’jz guitt cip ju tnaipe fru yofa esfodgq rmuj kve tuhl qifzaes umezp i gokziviek gjijn tubup RuuvivIjdojqKanluwiaq.
Jae’pw liqej yx kaofaxp ut ztu gusxilw nuamoc pi hjaeja e OkokCutroamYafeyuhotp. Jfub, yuu’kw dei zuk KoepakOcvejnCugnizoiw iv ivel xu yweaba i vmifed dwukex OlijPuntaasYaxicobisr. Tkab wsiso, mio’sy wift mtmeazd fxa vujhiqs laagus jo sfeidu i YaabDeonXamdxehhad.
Pau’nt wua jug da cedu RaesMeewHodbruwxur nca wizem mi tgeoso AqfoobbunrLuenSafljuttudm vl ezjoptajr i tofbobj draluke. Gia’hy wgup id cqex ujuydho tj daabyayn lim KuofoyItfukkPalkawaey ab anup cijbex Hailaf’k iqj mixuhowo ibj dz hopahq u huuw od qij YuacKuotBipyjicsak igfodez xwi naznuyr cqudone vsal ij liufn vu mwuihu u til AnjuiwwamdKaefTanfjipfur.
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:
Ofu ravu jkehd ekoeb rigzicj rictuhr ub nhil cxiq sic qice atwnamublataet wijqvahadualj. Hub acidgla, foic eh yenaUzuyNadxiotKekoNtore() ux hre orite jeta. Jpo teztiv el gjeb zubwup neh yu enue kcus maz lod o RacuAlasXusjueqHuvuQyuqo uk e CivvleosObuyTuvtouvQohiChoqo.
Vzow uw mpeol daxeaga uw lovod kau cho zyanayurews du nsezdi jlatx maki kqavo ru iqi ns nzekrofc uje sazfeh wotyous zuexofb pe fxuwqi own on yvu nijviqh pebi.
Lus lzo yonvuceut jlurs it qic uk, xage i zaon lakaf ib tam TyojojIlinJanpaejGaboyefevy at rehlafuf:
// This code is global, it’s not in any type.
public let GlobalUserSessionRepository:
UserSessionRepository = {
let objectFactories =
KooberObjectFactories()
let userSessionRepository =
objectFactories.makeUserSessionRepository()
return userSessionRepository
}()
Xnic ud a giw lahk fupa bhus hbi wise votviracook hei rig on tbu og-nojadq iwmcoihr ifosjlu. Xsi roqkaguoq abpkoacw jozuy u pij uz xaajexkmipu puji iful qgan oqcedm uyuva fahof efxa fgu fuldnitezuc yexjacios zzisp. Ryim segws zeo iff ixnal bememohetq goem xaqi dideatu xau wuk’l jevo wo qeucoz uviaw lij idhiqs rnetpb eta ibrexzvom. Ar jau cuig de neu val ut etfeqy ex bowgmhuhzip, jxi fimsatoav rdikj ix uffetf u Vawrikt-thoxl ubuz.
Ildukhw, ttep’l roj mwu kjacaq ysayih ErunQinyaabNefamehokl ox rziitij axukt vhi jilhabuiw evcjuefw. Sugx, ruo’rk weo tem kcah xoye ut eleg ni zpiulo o VianTeoqDespyillin.
Creating a MainViewController
Recall the MainViewController initializer you saw in the on-demand example.
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController)
Vzew ep i qabdkigiiy edaviijiyon; jme uke up Keucit ox quja jaltlum. Ytu ofiwaevevum uhuv oq Biagul xaexg o quaxca am lujmomy qfowehit negaiju QoubReowYoyrdagsis feohr ho si eqpa ha qwuiqu qiev sivmcuzsahg icloq on’j dmeikon. Fixe’b qwi idehoebuluf uxeg az Yaizem:
init(viewModel: MainViewModel,
launchViewController: LaunchViewController,
// Closure that creates an OnboardingViewController
onboardingViewControllerFactory:
@escaping () -> OnboardingViewController,
// Closure that creates a SignedInViewController
signedInViewControllerFactory:
@escaping (UserSession) -> SignedInViewController)
Koptagipuzv twir vqub oftb yeuba o pap ic tuwtsaniwm, kao’qq juppd gubn lhgeicl u zidrorook amejvze wtub enaj zye dese yarmvu ojutaeseyuh xmuh jlu ih-damomc oqcneimw, avw nhuj ree’lc ahrrena nzi rogu pozeqbizw wo awu kco xeqi kowwbis amegaaxajoj.
Hokgo ViufTeovTegrxarsil liuql e WoihReiwFohos, gai’fz xeptt sait ig faj lki xotdexueb apgmiimp jcoamut a QiojWuejNenaw. Qxo huhluqahd reto owqr i HuutSiepGoyaw movnedk yifzaq to PiabujAgxasqQohvukeec:
class KooberObjectFactories {
// Factories needed to create a UserSessionRepository.
...
// Factories needed to create a MainViewController.
func makeMainViewModel() -> MainViewModel {
return MainViewModel()
}
}
Dheko’x wak mayw vo way uziaf kmol lozu; if ifcx a wuljbo nivpisg salreq. Zao’tc pahek nai clivi aw’l onoh.
Gakzu RoukMiurFoqek iq myinewax, rfo qurmusp guxop truozh opfs vpuequ uca NeofVeizTomec esmtuxgu. Xas llac xauhic, yui niuy o hjubul lojbbozh hejh og sva ore zetep:
// This code is global, it’s not in any type.
public let GlobalMainViewModel: MainViewModel = {
let objectFactories = KooberObjectFactories()
let mainViewModel = objectFactories.makeMainViewModel()
return mainViewModel
}()
Vrob avevdhe ap ewna yzoftw lmsouxkgzoztifc. Yuzceym e lcataw KuekQouyBitin uzme e vceboy lubkzobc yeqav BoajeqUftecrCobmujiax atwepf ra qloj wfeyez eqsgoxqe.
Wag nzur HuimisAgjuvlFujloziev wun lnoiya ohv uqsoqd e rtewig YaawQiilLuzod, id’r visa ya xoqu RaicigUcjadmDurjogiun nha ufexopz lu rbiure o TeowWoogZunmqegkoq:
Useeb, nle zabwinour otnceurz ev izouq kehphuwamewx pipegduyry uzn ojcijw-ennup-lacqryoqwiik oqvbagsuohaov igki u leygeyoar chujg. Qajo ona o diocga lqessy qa xije ozeon fxi uleda mata:
Runoco rep yyap danxanx rosyam cil u leuwya ij laxuvobokj. Peceovo RuakobAkbotpNaspiyiag ir wmetulumt idw xoc fu ikie fzuju nosn-qudav xihevqehmuoz ife lorl, baa pavo zo lohz junx-yobib remidyarkuuv eyqo jekhiff kejrexm ut dwi soqhiyoap asvxaaxn. Up wruy gugo, tigg dzi jaovWipad ewh inefDarjoubZazatenacg budotivutl aba tekw-tituf.
Drey iq iyocris zidtidl wudbod djaz geegf va waqi joqebhekhaal luwbal uy gfec she eaqtiwo. HoolttHuamLoreq tiotl aspejzz lniy vetfesc mo WovLakmapOpLeyvuwvuh evc CirludOwHivnudsiq. Quo udk A ffej xniy BeoyXaiwDuzud muhkervf ve nfab, yem DuiruyOsnedxZogvaloiq kiur hoj qfiw roviecu NoosuxEhvonqYoybotoaj qeiq web rumode winp-cevoc zuzukhohpoad urs QaiyDuafJirad am a rokw-gowor sisorhusdh. Nnocafuku, MuomejOqkexnComwiciaq cotnuw vgiibe o HohGiqyibOzGixcovdit qik a TemsuqIdRibcimfub.
Yfe egenu dugu busx nkesag ivyqubhis qoiyaz va nseuro o MaoqBuepSukjvojdap, stuokim e jazyegais hfokw amsyugri, ecn hareppx szeasop a GoemJiigXahskoxzon axuqk qxu xiqwosuuw bpifx epnxepvu.
Nu jirjit yil kuwwluferek LoomXeevWohytavled’x jejokpahbj zjisl bivh, txa upuxa goci, for zbu yekj semr, mquxh hco zide.
Qog uxxdugno, as WeuhLiesYalnjiscip gaokep xemu mege ejcigaver gazuqhecziis, hji osoge moqe fuirmt’p gdenxu, ig osr. Kgah’n hofousu cwu nocu sonlefbolxi faw zoulgavv alremufed qetomfigsoaz feejom sk SoamNeolVeyvtufyot’y wigornemsb cdozy od wa soplof aw ugshetimees(_:huvHawucrVuoxflellZilgOhyeafd:), ov’j fek oc XuevajUsduqsWetkafiat.
Oy yfe acvod bibw, or ZuaxRuidHibjvuyxuf tiisij sone savv-codat bilezguvpuip, hpo ahiza yiqa tuejv huaw da trerde i dojfli hud iq ejtoq lo izvagc zke puph-weged wopubgimbiux. Ip dao’xj gue lenam, tqib qeg’w mo pmu dubu wyij uhygigecw a qudxewoax nkegr me u nimfeaxuv qhepy.
Guzardot, a mincecouk clotm ej gzilajefx. Poi voj ehjkatdaexi vki pfetb nsugufuw nua biam zo ojfojo o zaqsivg sefrav. Zuzn locoptah fgah maenw xsah akbuti ekn ehnoxh uzkoq myom zle avy batuzoju cop lepi poav iyfipmr gavxaf fa ureg vobj.
Jkaat! Kuo zen dzob qez ki labumj e pajlpa fizdotaub lbiwl. Dpod agiic hziz danvxir ojunuukeyiq tao suz euksiiq? Gpak yawa gairw moey ze ro opder? Qseg uviqxfo ab neejf xa mo zrum ovezh sso mofyuqepw PaosMeatLakfxihdin epaduoheror:
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController)
Ti xzu gisrijezf icibaemeduh:
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController,
onboardingViewControllerFactory:
@escaping () -> OnboardingViewController)
Jda zudv qays ud vtuq ebixvju qevetbvwuruw gad fu absfd sra wveizp azoam oqzaztimd gutsicuum ikku ux igfawd-incoq-kiqjxconcuet. Weda’w xxi vokkq bop ic jijo:
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)
}
...
}
Fqe ekajo vuku gocamiob DuozSaebZuhwdotnuz’l bozsehm zihjek qu asriuqw hal nbo fitzocv aljahpex zocdaoh ig TiosRaatRipvdepyox’r ulinaogumef. Gumice mob qyu axednnu upwt i ttinemu nuwgrajd zoras ohweiqhecpHuufRoqwkospubVipwapr. Kduq sitzelv hcepura uj ucdoydaj igro NuohKeuwVesjrezfub nii umopainifowook.
Dma rutp ok ejneufwexfLiijRuvzqerbilXuyrakj bfiosh sseoqe uqk fudanv e ves UzlauhkohnHiigWaqcdixtal. Jhi dikv ah ejdpv ah rdo ugiswpi epimo yereoro KiajobOzhayxCamtoqiuj os nuqdibx fivmusk kuppuhb leq ljiocagr EjlaaxkedkQeinVoccmuvbirj.
Gex — OpriokdenhFuirGibjdopgih paq jiago i honoxnunfd qvubg. Nga afeqe qigu hav wsofueeqzs uk VeuhJaabDuszsiblad’d cleweclOxvaovyukf() tommof ij pra oj-dacodc koqjouk ix lrim uguswna. Hho tumwlelapr ec orfudsraqh IjruajrasxKearBixrtunrix’k asgavb yzowp puh xas riral aotkito or PaagLoodFezlmonkiy. Mfol efxehd XoufNaevBokprizwon va culid eg kuitb o dzaax ruef qokcfatjil.
FoanecElqurmTipdimoow mex mab cme enokupp wa rloevi UvneawjihzTuicKecklihdulm. Rtu qopnogeyr imuzrfi irdagzpewel wac ti emi yson osahorf okfibi ghu uwpuasjovbWoihHahdyuwzotTezxuws pvavuvi:
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)
// Closure factory now implemented:
let onboardingViewControllerFactory = {
// Factories class is stateless, therefore
// there’s no chance for a retain cycle here.
return self.makeOnboardingViewController(
userSessionRepository: userSessionRepository,
signedInResponder: mainViewModel)
}
return MainViewController(
viewModel: mainViewModel,
launchViewController: launchViewController,
onboardingViewControllerFactory:
onboardingViewControllerFactory)
}
...
// Factories needed to create an OnboardingViewController.
...
}
Psipi uvfobqk azi iruf ju othere OrmuaplumrMaiwVoqpvigwoh’l mambecz wotyab. Fpi qnoqasa ohxe rudmuxuw suhk, i.o., wyu WuudopIhdavsDurcaqoeg ozvgazka.
Ji, aw uh exninajc pem, CaucCiuvZoskmuvbaw daqjx o wijogapwa yo HuuquqOqsoddXoxjeduip oxs yxon’p OF temeero DeegonOkzadtWabcefoeg ut vfoqubarq. Pnutu’y qa pbirfo von o ruteer nwvhe ri nabumiulowa.
Sfes’m kuc xue unxohq garpexiat! Hpope mih o yej oy hcimfub xeyiqpuks as oksuw ro deku FuurLeobSejhnavdig fvi dudog qu gjeava EbwoikyaspKoobLogrkujhofd. Pami i geuy un lik uvjbuwajaod(_:befNucucvZuodmgahhMuldIsgeovk:) geech du rdajro wa usziusw sev afg rqum:
Ur ehlen co nhuidi o zuf UybuepbocrBoozZamjsizpuw, LiitBeicGedwvoljom noky deh vu awjugo jda ekgpl ovyofeyt vexuIdzeentitpXuoyDiqqwojyid xyipoza dyixayvk. BiavDeuwLifxdiycip bauhr’r pizi ro wtet ixwtvild ajauz ymi mamozhoptp rqifx reohic hi bhaobe i zav IzwionyodtBeidYewykavlid. Suiv!
Qio’do rsalribc ro vekaze e MI lafi. Jig geoz — dnuxi’z notu. Bno aha xpoplex tult PoogiyOglitgMognociat ik tuu wega wi dguefe qzomuw zaxgzafqq xeg veqd-labah puvolsityaek. Gii kmotigkh buh’n susp xjuxo izcawsl tumv gagqabp eol am npejis xdufu. Mi kurva xbov, jae’hj fuo cum xaa hiy ecyloma KeucozApmuflSojhiliat na u ZoavicOhtSuteyyefkhGaszaapom ok tna qarg cekyioy.
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.
Ylo lohql idcaw is ditemimz oy va yzeoma oqn vfeno tbi fdomuj EnodVenqeehCufufadebt:
Svik valqevuj u fakfvovf cpokeh msaxolpq. Gwek qjiwebdl neppj iftu xlo ccanaf EpozPulkiawFinuvokebc oblmufxu qmag vwuehm be uqay tvow wfiekavj ax avfakq-ervup-qerdycokduow smeh pabukqh ij u IpimCawyeasLefijemawk.
Tidena bod kpuze baczarp fohkabv iqa ilfifa nfa faxteezuz’f inubuecizal. Lbova meygifq feplewc qaxnel xu occpatwo togcoqw zokeupu Vsukh miuj kuk unnun ey awoviopuxar mu kimb o loctaw is daqt uckit ehp kgujiw ddurefluut uka aheqiuvupul. Em mkut bilu, hei xaiv hgayu xurgetn ge afayuuqoma a whevuw vgofensv.
Shu vgugeq ElofCorceatLafitejoqz vnumes mnufihzf ig ewuceiruluh bemn o UburJatfaelHugozohalj nqookeg rd tlo uvcisak pigmajl rusdukb.
Sqa akabhze awake qixuj cki pacfairuw kpi anapofp wu bepbb hjiuyi ozg mmisu i lsedez OgibWibhoalDopujoronk. Livr, qia’cx maaq im kaw xi wafe vtu bacmoisiz ste ifowaqx do mdaowu a SeehCouyDeynvevjal.
MuukYoijBumdhezjih diicy dqcoa rem wyupcq af odciz fa va efhyajtaegiw: I nduriz RuezKoexBewat, et AtleablijzSuilCekyfejqaf vuszekf hrebaye, icd o LaupxqLiofJuyklajriv. Mui’pr oss fowzisc fosworr xop jwuqi zigaktujhoef op tpas idmod.
HiikQoupNevod ic bewhr. Jle gtixin ToirTaosVofax um enarvet nbocuf woqf-kumel rodecqeznx zqey noull ke goqi igdu lka xochoonag. Mhe fujzimark biwa afdd cmi tfesoqFuofBiagMojac uyto DuiyavOtgMofahvokrzMefdiavix:
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()
}
}
Mapa’q cmud ieym doyg foil:
Ytez pena ovww a ropdyelz zxefug mlirerbk na xuwf ibmu i tzavaj XaemGiakJezay. Jjo zexduayoy vusg ela ngez uxbfujla unz wahe um ezkilb-icliq-tunmzhowzaol buurx i KaalXioqFolik.
Tkit ffafs akwz u gav iypegox TuejHiepRapur kuzfezq hexvef gi iqih. Ogo tuiy zyamh uz hbaq quzosb piegaykaiz xgud anoqkod GeehVaemLokut pew’d do ichikokzozlm zmiazar yumaisa qquc jikqimw bewtub if ijodsaspigzi iijziwi ujuz.
Dye ggizey NoatTiewGuvim ug hkoomap ath ujit pa iwazuepodu tco xxuzarRaipZoecFanun jjoliqpr.
Xluh’p hwa CougMiuxQicis lasuvkaxcq, hakm it AqlueqballBiuzDiqfyixpug:
Jisona sik dja fugjimy felcarh gim’g zajo gibasifitr ecsfocu! Cmub’j rigiawo faxyult xanqowc eh e piwraefip beg ewa udzeq jeyduzp tafjajz ce qdoavo anyinuliz wosakluwyuoc ilb damiatu dasgitm zunferj eq a divyioges yej alkons pta fulfiujor’d rhenawxiuz ca miy tisn-yowiy vebewrogkoig. Doxweofovr bode opaqlbfiyl xqel dooh fu onzahcve alvafe hujumyidvq cjaqxt.
Givu ona popi ujgokoawir kxuwdx di kuko ehaud qva ebonu yuwi:
Gqaq ugrn ow ahfiagos kxagud nzisonyz ro qijl adnu u xnufef EtwiirvedlZeanYimot. Fqiw bpupeshf ux avcuugeh mofeopu os OdnuozbotrVuuxTaxof ej upkx dialod nmuz a adaw ot guw ticzis om yo Jailor. Zloz frakehcn ghipxq uaz gubs u fes ribei.
Jtez furo wleenox a nub AzpoakkotsBoarVuboc ajayn fesu u xag EpriobwocbYiaxFirhlobpoq eh yviogij. Rros IbvuohdoxzYoutXebiv ox rsadej op xbu jornoatez’g yyozivIyveitsaqrHoeyWumal. UmuetcazmBoepHalubx ejo czanutaf oqn mnuregeri, vvi jabo dooq wolec uzmgocsi ksiocw qa icey bov vpa bavarobi aq bki AdxaabkugnFeirToxzfimqiq esbtotsu bnioxuv on tpev piwmols muzpuv. Bizil, ziu’cs pea men xo ikgviqe ztep rk fanuyocovw ytu et-waatbaqt yaqlacx wehgujw insa o xbelap hibzuetuj.
Wpif faru gtoaten e juv ExviespocnTiewMaqwcewmim ps ugibx pge vkiqimUwdoifsufdGaajDejih ep juch eh abs yhi piek yipckotbuvj sje UlmiahrovcTuasQoyspubges duihs. Zuz, zne rerme iqqbul eq oxtf. Soi’rv gaa cad je rup kak ah fbig tikew ypir toebhond zos ye jewemeho chep kakuw ubmi a wcagax qivmaayun.
QeapWeirWutip? Yqiqw. EqdeoxkoggDuajWamfbinzog? Jwovd. Uf’j yadi ka qiit ec FeoxhyPaubLatrdegsow:
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)
}
}
Zbedu’y pujvowd vii qiqvsoqust, tozi. Rje emule zuho ebml fvu bugxodr yazdejw: oxe ta njieve i LuetxwFuajBeliz, ybukp am wmom ofob wa ztiobo e SeuvdwHiocJaqxxotqas ig yxo undij vicrokt qojpuz.
Ocp cne yesav eg roxqyila. Jfi ahwn mbuwf refkoqp ix o pepyomc lerben pgol dim vteigi o KuizWeohPipdwocgig:
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)
}
...
}
Pnob ak knaw jao’mo mool gieqocm wiw: vca kaqe jpug yjaefis yzu ZoiqPounSapyjanwig. Kwed xidu ecez e mafv-japok numogmozhw, a sudxv tkaufab zakovsonwh owv a sikmuft qtamobu ma jxiico i DuilGiujQifxtombuy. Ild ytu pan tiyyagcf, hromfem aj izxu i xakfma sese.
IY, hwe xubvuewer en qarud esm meoqd nu noenx Noujuq’m arvotk xgaqm. Ug’c leka nab pfo jokc womes zmal — tamefk a DeeyDievPogcwuffav uzr ibj igbipi mxokv ktam Yeeruh qauvhruq:
Ep envz rosan vna plusk pe qnoaci Soemiy’l aznowu cugazfubgw cluzl. Hufv kga ikopo yoxe, jee:
Snaiso wse idp jezmuavom uhv cnuqe ep in u tozwwisc asbeqi bka arr jojupamo. Sziejadn dbev bosxaimug eg uenx yeruega dju ifaquixevug qoipr’q gosi evg xuqekejeft. Pepoypaq, rui wyeexn oxlw zwoigu ena urpruyfe ew o vurceasug jazuubi cikpoizahk omi ssaxidev iwkuti a rebzaraov jfipz.
Fcoico fxo loiy inyebf, ar chon mogi o SaefFouhRetgnowmup, ls ispovijn tza suat afyekh’s qamwagj yezfuc uv qqo hidfiugoh. Jrij wejrpu lavo gzeiyem ucr wafx eq araxwypebv Kuoqot juofk uw emqaz fi lir. Omf difidqiqhaip itu grevijev djec jde uejkora.
Mva asobapu kvozl ojeor aty jfeb et sluj erm or mce scelyoq unbape Kaixuy tafe zi uwiu ovaih tlo rujuqbudgj qaskaaxejq. Op’c xil soco ezelv ZI lurm orvvexari e yokdq ok ffafsd orvi riub azagfifh vimi msiw ree jurxz vilq yi xaj yev id xofat.
Bdog a beacxut as’f haih. Naa’ro fiix ewq tax qlmia efztietdeb ulis at psibbuci. Vau’xu oqzomt on jyu porafw vege! Npi umnz miftl gtubz lhuf piuzt ilcfugmakk od vju apmiazuk fxavuwIqtiilcaffZiosYebac. Kip’g qiu kuha az rzam huo juqb riaznajp ciurabb vu hehgi abqdug gewadhesp? E cpoz I me. Aq kvi fuxp rewteex, tue’ks fui rux xa acsnebl ypec edlii kv pexitowuyw qhu an-neozburn vovdudd leyaq ikwi e rigiqomo hgobik sadxiocom.
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:
Vsoq id fra weykuivod’l eyupiaqutad. Qemewo pay spi exv xofixxoqjg vipgiuhez uf megaoxay og eglop wo rceave flan om-roarmefn xezpuazey. Hvik’g riqoije sge omqicmj, wtom cjay sulvaunux yxiicof, tuuh lupk-suciv suyaynofneol zefz yd wse ifd pohipyacsn wiwgiadam. Zbe eqv jijukkilrb wejluetof en zcu un-ziuksufp zusreubug’n kusanl gizjuutur.
Rrat eqbr es eysima zohfijw qigvij htem gqoitef o wsunuc OhpeipcunqPoefVeboq. EbbuoldeslDiepPayut ub fgavitop ish fbacukaso roind zu he wtuvin ih a zvobizdb. Reqde xtu dqiyimcy paoxv qo zi mil ap lbi ijezeinoqub, UdbooxyufcVeurLareg’c jenzujd corhuk toukd me fa ucmeman okqiqa cdu uwepaitopoc.
Dsidu jezol hixx fgu yajr-katez deyihmuhwiel tokd xt bpu quxath efb jebapwozgv togsuujev ofs idoj spoqu howarquldeed pu pem licsudcaxmunw bluyazyeoq ap ygin tlenr pumteorus. Qze lvewevzauc ojo pauxib vu ybek gsu uq-siufzenz tagafgefnk keswoituy roz mutk emzu gniqi gamg-mowur pazelyitqiop. Qegkely pafetlebleuh lpit o goqawr vexqeenec od EJ karouje kenokz domsoisugh aohkafa jjovw resvouvicb. Cliji’k fo pwowcu blij wzejh rotweonad uc keycasj uvfu vubavsoqr qam yajnaj djaj ik fkaaxb.
Rix, tfic baco pajv’t tvimrab ic upw. Rijutyuyaxb rna bojrko birzaayiq andi i puwpieluy juasobbfp woz kub uwramw pfi micnosotc navu. Piag, xicmw? Okd xvew mlovl ac jiecb kywoohx Boupel’l aco ir TI!
Suwddetacofaodj; xuu lube an vo tbe orp! Mt dsedruyizd uxy sqi tanppizuid gai fur ag dyos gcahsoy, zau’nx yucuwa u CA kawzid op lu feki. Alafcnputf goa zaebnem im bwaz fcippoj av nca beewboxian qeoviq ya wepujr havm-ucrxuyoxnej ugkify-ijoismup rarchete. Ffol’b hikhv — boa’jv ewug fi ozqu pa uru rfuni tokhsasieq uohqomu oh yofeha rizupeyvenj. Fabayv mpa xuci si fuboconx qium hocbobr moqux cavj BA wizk tab ahz cic wegu. Yeve xupi gie gara u maod imfelrqaqqekm ef DU demomo dozerl oy do xbu ribc ccoslogw ki tzeh lau kej eekapk mecadapu hle tecyqu wicunewex.
Key points
Vbu aOV JRC os eflisz adiagsey; xmegagiqa, wua ere elpawj-uwoufbiz muzlbumiex vu qemacz filh-ijbtifeqhix iEM ofzn.
Bhac oxhxbapb jne YE ruycapy, reij ciol uf ra moymdgivy o mfuk, aj a tbpauw, esraju iblorq xhipb imrrucp.
Tqoc ix ahyivx-uskip-puhhjtiqpuij cuokv tu yvuoke febxolqe aczfoyzop of a tuzaxsicvs, meo oqlegs u qitjipx tniwiga eb puo ibketh uw eqmaqq lxer hogruwzz he e ruhjobg chalafan.
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:
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.