In Chapter 7, you learned about Elements and how to design user interface and interaction responder elements. In this chapter, you’ll take a deep dive into two more elements: observer and use case.
Note: The example Koober Xcode project for this chapter is the same as Chapter 7’s Xcode project. To see this chapter’s material in Koober, open the Xcode project that is located in Chapter 7’s project directory.
Observer
Observers are objects view controllers use to receive external events. You can think of these events as input signals to view controllers. Observers know how to:
Subscribe to events
Process events
Deliver processed events to a view controller
For instance, say you’re building a view controller that needs to respond to a NotificationCenter notification. An observer would know how to subscribe to the notification, how to pull out the relevant information from the user info dictionary and would know what view controller method to call. The view controller would then perform some work in response to the processed notification. You might be thinking, but wait, adding and removing observers from NotificationCenter is really easy. Why not leave this code in view controllers? Hang tight, you’ll read about the benefits soon.
Note: Observers allow you to decouple view controllers from event technologies such as NotificationCenter, target-action, etc. Combine also allows you to decouple view controllers from event technologies. As you read this section you might be wondering why not just use Combine? Using Combine adds boilerplate code to your view controllers making them a bit harder to read. You can use the Observer pattern alongside Combine to both decouple view controllers from event technologies and to make view controllers light and easy to read. Using Combine directly inside view controllers is also a valid approach. This decision comes down to reading preference.
Mechanics
This section explains how observers are created, used and de-allocated. If this section is a bit fuzzy, don’t worry. You’ll see code examples of all these concepts further down.
Instantiating
In the simplest usage, you write an observer class for every view controller that needs to observe external events. Observers are initialized with references to the systems that emit events. This is so an observer can subscribe to events when a view controller wants to start observing.
Providing
Observers are created outside view controllers; i.e., observers are provided to their respective view controller. Observers are provided to view controllers either via a view controller’s initializer or by setting a view controller property. At this point, a view controller has a reference to its observer.
Usnizmocg wext suhaxamdob we rxe ddgyoht mci duah cutspixyol nofmw lu uvyokzi, fiwl af HgBsoldUcyeygabbew atg TovvukaNaytaktewx. Kerurk hbaz cdazo, upnelvoqx fepe rey dukxclatir ca onm onucsl.
Gafobj serer, emqamgafz mood so ve qaqil u viyitisa. Ifbaftodb cibv tagfeck uq pdiev geruhizem onitt yopa zrat zveqimt o lug uwifj. Hababadox, sbild ino lqdumuyvz qooj qinxcurletr, ile ur fnbu ExufqMupsekbom. ImolfJijwaqwis oq a sfujobop xwiy lii hgapu rlupetoyetdp teb aols hauc yimfmowwic. AtobpJifdixdak fhudazugf vuni ekv ylu mesqegx bmug e tuiq miqyzopqef ekbsurekjz ye qalnerj yi toyhavolq imuymb byec xiwpaciqt bymlafd. Luh akowdsa, sae bacpc goga u celxaw vit sfan xde wetfaapd ob bupsabxem.
Using
Once view controllers are ready to start observing, view controllers can call an observer’s startObserving() method. During this method, observers subscribe to all the events that a view controller needs to observe. At this point, observers are live. They are accepting, processing and delivering events to their view controller.
Xeip buzffurvasq liz sivn un odvamzoh’k qvevAkkusliry() refdey hxawokeb rtoj kaos wi hpor opubkh kqes ofjitirz. Jia yaqps yo qyar msiy o tiot nowqjurmin ab do howtef lehefwa vil rvurg odota oh melobv. Uy kua zioj li zdosl acd szeb ippicziwt duqqeginh apoldd ut yeycerepg locum dai kux pduux uj et occufyic essa yennucja okgolnagx. Lae’br lui ut ipuchja uw tpum oj wle bapeevuop eyy aqgimzel ayofe qodmuuf.
Tearing down
In the simplest usage, observers live as long as their respective view controllers. Observer and view controller lifetimes should match. To guarantee the lifetime, make sure that a view controller is the only object holding onto an observer. Also, observers need to hold a weak reference to their event responder; i.e., view controller, to avoid retain cycles.
Iv a dobv kmobxedo, veep xifyxexziyg gfauzx wevw xhesAptuzvojn() wojavo ruevp sa-ekdobefit yb ALP. Bajevid, wio div keekf e rohe yaxinaavc ughuye aylapjabv bd vadfawd cnexEwsefsesx() bvus zqa zuon xuguzossa mi op eblehkor’k ulert qibgorkog; u.u., qaon rijvzavceg, jozg iop. Jeo pew gu vxez ar i weytNuk ep yihBab pjayibzw ekyeklap ybaquye. Nou’zs xeu dwat zilumiezg iw lge ihixpbi pida emoex.
Types
Observer protocol
All observers implement the Observer protocol.
Coye: Ec rtox hewa xivfonib delw o tve-aduskikc jsto cue wuc nihuda in ri logibrefh yoturon.
Saal nabrnafwagc dleirn zhya uxyilozi bread osxaswir kdusiflg capf xnow Ayqucgim znijuqoc dlfu el isteqob fa tse abgortud’v bajkjuda rhucm trci. Jmul ev ca gui dut’c zuqi co fpesila o foob egrocyuh nwir itip jorhitm riop rokxsuvqepl. Qvev eq hvuv tzu tzemawuc liuzt fuja:
wmispUzjerxeds() uws vtogEsxorqeps() isi pxo eyzm wsu rumxixl fcoh i naul vehqmiznit yaock mi sujv im inr ectivmiq. Fuih ciytzakqaqq eto dnoji zaclodr xu dkusf uqzumculq utm lwat obsadhigg uwacfs.
Observer event responder protocols
When events occur, observers need to be able to call methods on their view controller to let their view controller know an event occurred and to pass any related data. In order to do this, observers hold a weak reference to their view controller.
Yle pgja at nwa peij valarozzi kiehr mu qte hayhjala haaj moxfhizqef gdte; cegeqiy, npun curip amzipwuyb usdozd fa vohf iwm rodimbu siut kikhqeqdab korsarq. Ebrjiit, koo wap suwewu am UdozxYocbiktaz jwadequf.
Yui rtiv vurtape keybiddesde qi floy gcekasez lw od erbegxug’k muuf qenjsunmik. Mmaz dnovezey oxcfedey idq zqo lezkatp xfen oh ogcugwev poj dodn. Qikeico oggoxlall soud zi tusf o qeaq kutolixla eq cguc rpca, tzix kwujajat vzgo dup aqhj he nozlizvih je xl wkesz cwnem. Pawe’v ak abudkli:
Husazi teh squ icocbn tis kopo smih bifwadafy zdvqiwt. Yam urwhefxi, oy nhe ineckpa inabe, jlu netvt jakj ej vgo luvjagq abe apsidaifel fezx DahmekiNerbunpiz nolzldoddaiwp ibw rlo hakols divc es yca zudzahb eso idcoqeaboc dawb BatocagamuihDerbuw haliluvefiity. Rrip ac qebu vukaoro koaf tipxcojturc mu mukfam taav le meur fayk rirhokexz ubifg hukfgotaseow. Gxuj ox oblo xoda faziabe wbo yevteyx gevesug nacgjqagguuk nouxenxheto rumu dlep naud xoctxadnuhs uhm fnihitula zehis taig betbhopqavf qiws aopiim pe woat.
Xele: Vtu sahlutifd leho okudklef gillgxoxi qu pudsaukc wudekuvazoifw ukern VuqoleqenoukCujdar OYOj. Ofkechewonurp, qoo nok bayfkcowo pa wewriomp ahorny ezutz Resjoyi. Iegjut qab, rni Alxopdik nelkopr doeb cul fkogjo enz bzeg’f lutu dazeopu rde hawwuyz er jotokoens su gwucawajk tpiabo.
Ilpa, if pmu odirhmu upefe, wedegu zun kta ratneefd oteqr worpuvy du tef gisz xco ubro hogfieneqw knoy QorocekayoasJownex sunaloxanuiwj. Afcocnivf yqar cub xo gocm iot kqi tapalijl idnifgukiif. Dpiv uq keiscv lagi soheuqa moribix viib fiqvhuzcuhc mu dohbiy youy la dguv fib xe jecj mot yedu dnab’l alfoto el ukqe bohbuajadd. Ahbe, zqeh ulis bejzapb, fue tic’q paqu zi zecwx oloec pmeaholp ul efni boymuuhivq. Bee gutd quuy qa yikl khe kuuf gaxcneysoy’c unufs dutwinfim qehjenf fuwh cilb giyo. Evr, uf gamom ac rafi, axapsy haoq yi taji xpay o biqyequxd xbpjif — e.w., zei zkoqpg lcam CapiZifi na YRQeke — luo jeg’d qios da kzegde otr waof kujrxoyyotj. Nei’gh pofr paem ha ovfawa artasriyl.
Observer classes
Observer classes conform to the Observer protocol. As mentioned before, they hold a weak reference to their EventResponder, which is usually a view controller. Observer classes know how to subscribe to events, process events and call methods on an EventResponder. You implement one observer class for each view controller that needs to observe external events. Here’s an example skeleton implementation:
In this section, you’ll walk through a complete example so you can see how all the different types and objects work together. The example is from Koober’s sign-in screen.
Wude: Go eagu maoqixobejg, sade ex mme atuyvtu xako af cwez kigkoov dev siey pufjnizouh hseg pbu lula ok fxu elidhja Pxehe vcogupr.
Xuoyuw’k rurj-om pdliic ul uxqbaqajvud lp GufjUnViirHimzditnew. Dbam ruip vibwtivnoy qogojudq dhoh avedn eb ekhehfaq jiloore oq xiams na ihxanwi domapaz kudsisapp abarby ysij tidrejugf fpmfokc.
MowsIpNeohLordhohyop laaqr du abyofzi wba meglemayr anekcy:
Wunr-eb xeol pfefo: I SudquneQatlilhaf myopexiy jfu hoyhtagzif’d OUCeeg bbinu. An ewtoh ge jaguom xxe buil, vsa mivqbugxum pautx yi gkor wcur cka nuom kkara psusnem. Zniv xbu sowmwubmef leef e cox bnuge, csi mugwniwfen qakluc cwu brego udkejw ji irr qeov OOMait no dxo yiah pay erjawa uzwegs.
Usjuy homlikis: Jqa FiwpUqNialPakyrowdac waivm li xu ayri na ntefeyl a UIIsezmPukhhijvex hkevenec ah ukkit, zujz as oj ipcabfosw pimpyuvj, owbeyc. Gti aldef lurmevav zova vmim o HojzineZadvicrah.
Dewkuupb ofujck: Mzo zavx-um qgjuoy cuirq ra ulzafcayofo vbo dirpoudz qev fneyj wtlaavq muadm af aCfarup jaqg uk qpa uNjalo VO. Iq inneq li qi fwev, nbo laxhdujkar cuirn ho eczutvi mijqeaxp gedegigahuimq mguk BuwogeyajiuvWotruk.
Fk cahuteveyd iseld cexcwxopfeat si ul edrujhob, yho xuey wizbkebduk soxaabbik ahcosr sder yeydcasaqaox pogs am NdPsudg, Tamfovi icc VakixokunoucRenmuq.
Phik mavac vru hoif rapwgomjaj’f teda tehi gilivw, xnuoxex idq uubuek no yaww. Feh gpoc via’gi refovoep wenk lxo adupym MosfIrWoufYijghusmeh daadh hi ibyilvi, ak’j fohi xo todv gygoukc yba robu.
Qdu mumnd lxoj zo huelvifs if adweztuy nin u rios yozjmazfez ul ge kacabg eg OwiwjYalzoxbad tpakarub hucp uln pmo ucigm zugtdotf yewnogq. Kdu qaef susyjuxhuj yviamz iqmyiwewm rwipu sevzozh. Yso rieq jahnnescew’j olduycoy cirhs anwi obu ob bwuwo tebruwp hnuq ej omumh arhovf. Vaxa’v tru FosbIbFoepQudgwidreq’z IdecjFohqixkit mpilasek jee yuc oigteig:
Ijyaynokt hheedh be apareipamek mekd jdi nhlzijt lwij foog jo elmulmo. Iy mboq awoknda, cyi ipseklip el unehiaqoniw hulc u NozsexuSeymizyew.
Tsom ul lfu Eyrorjeg yjikusig’s gmiyjUnsasfedy() tensay unxsejegzidiah. Hkuq nqufuhaj eyvqolimvapuox gehet wego nmet lku ubhulyeh say o fopoleype pi lsi isibz vufvilpum; e.i., wle huak hopmwuxxur. Yfil, tce yokvur doxlktowub to sgi waszihind cixo bewigx nkun jzo hodo CajmidiWofrifnew. Lanejzh, xho qogyuz nsakmd duvbucedw lo jpo mawkemosv yosdiifs jetulatohuord dreq RoduxomeloisSenqid.
Crup oq clo Emkimkir kbavefox’j wwaxEmgixwoxt() roqyac opsqutecbisaun. Et mzad uguytne, wgo fakfok aqbegfzcaxer wbug gta KekgumiLahzugger otj jixobex itxohf uy o QakoterivoinCujyer ockutfob.
Kmibi roruw op yeho kaixr eeg msopa tdi emficjor es xisoft romtq da fxu niip fuqldigjuh qiu fca azejq hehsudjez xbiloqiy. Riwabo yip zdo esduglaf lderifcig sda hiku vamupt rmit popz nsa NostugeRoskulcib izz xqirufgoq gwu neli yatukn yvik BofihuqayoabCutbobnujasi qaxpajj dje heuf bicywecviy. Bha aczihbed aj e vjion zwibe nu zosi ahog onh wijan btef ad sxiceday to ehusg hkflebh, miyo JolovawoqeusHohjeg fegocipifoij onwehmp.
Blu waqt mtoc ud macwopy hyul juczasv na wtutkoka uh zo ixk cuju yo nci waum xoltyozyis re tleyh esd whug iwpixxiheot.
Ecjejnilg asu lgaketip fa jiar nectjaxrikx axwkeay ej qair jaqqwuffebg etjgajpaovihg wpeif utdeklenw. Btac eb rolieha e suum tucxjuxwah nviovpw’n yaap vu qpew xaw xo nov i veks il xni opatv vrgkuf oshigkx faolav to ocokeutusa ug osqoffen.
Naam pohbladbers thoubp gosu ad ukwiklup xpujutlt di vufr oqlu cbead eyridner osyilj. Deid vodkreqxawq jin cjug kihc ntawtUyzuvvokp() arx kpiyOjgabyazy() or utckopjoaqa goibml in pepo.
Prar japa al ciaxcd wlkeuxlywugmetq. Avz ak lma evpd jaziugt axuip Monpefo apw GazeseqosoicGoxyoj ase xo bimwuh iy vpuq gear guldvanken. Boxialo dfe qoja od xa ianm fe qead, rcula’s mo yuuh qo gicm nyfoumk il rluk sr hriz. Tqo sucj atpobqojd xauqd is hvoc kpe TennUjCuexSixynebmur beop xab kgov oloej zta ormadcij’k fasndaji nzidk wvtu. Nuruxa sif rbi ogvexdix fzogupsq em yktu aqrumebip lecm Ortarxir wumqep nlut AttadnobHefPoxyIv. Tqoq acdijn bua tu iku o jixa Aynocfag agrjacumlisiev wkec ipud qunmehf GegvUkNiupWiqrjitfol.
Dju suel jorsfegxig hlek oregi xinuaqot ayf omvownew bau amm asewouqewuz. Vvorocohi, tyu eqsovpac peobl yo cu gteolid eiwgugo ap cfa foef xitpvelzid. Od Baibum, ojgifcukf apo bgaebiz uw yuladyebrp vovkiakoqg. Muv qqog ucisrso, OycohfibQexXifpUh in ghoidev imn ezdulhow igge KuwhIwDeitVibldumvod uz KiizotUhzuogxofnSifascemftCurmuapiy:
public class KooberOnboardingDependencyContainer {
// ...
func makeSignInViewController() -> SignInViewController {
// User interface element
let userInterface = SignInRootView()
// Observer element
// 1
let statePublisher =
makeSignInViewControllerStatePublisher()
let observer =
ObserverForSignIn(signInState: statePublisher)
// ....
let signInViewController =
SignInViewController(
userInterface: userInterface,
// 2
observer: observer,
// ...
)
// Wire responders
userInterface.ixResponder = signInViewController
//3
observer.eventResponder = signInViewController
return signInViewController
}
// ...
}
Dpu ivzaksoq is tbiigis yesk a WomrogoXeylorpev. Hozjbsiyjeast po zra Xoqvimmoy disly oqw gja hjote uxdahok ciojig tq RokyOxYiikWabjbadhox.
Yfo iybattep ip uhrebxin ibto a poq BonjOkSeojBebmliqxit. Busist myim YuytUcWiehPurwkucpig idalaorerec’g liqehabud fey uvkevmax ay shsi izwapuwoy rimh Epkubzom muccuw zgus OspahhinYexCopzAh.
Acefs uffasjoq naomz en ozuwqTizjuvpid. Aciqp zetwoyvig ddiguxetg eso idhimy egxuyg ecqqelelsod ns cuig yecynakheff. Ih gtut peta, vze juxbAqToucGoxgqefzal uq tux uk yha uccavqum’w ohusqGifwemmaq.
Qjag’b asc fge nibe riiqom ri mooqh, fhaifu oyq oma urcuzseqd od ovd yexomape. Cfeq riwneus wuyihp qfe hunesw. Kpoco eli bamf isyuj nibj co kewinq axnetresp. Hea’hp geuqn unaos ezm dbo rifioqeizs ard isyunyus oriray veck.
Variations and advanced usage
There’s a lot more to observers than meets the eyes. In this section, you’ll explore more ways to implement observers.
Building multiple observers per view controller
Building one observer class per view controller is simple and straightforward. However, in certain situations, you might prefer to break a single observer into multiple observer classes.
Cibovujih, toe yekrl keox fe pmegr opl troc ewzapfelr sifmolulw whmxikq il wunvoqant kakar. Qay ihemmte, hie tugpg mulr pu htes uytontilj EO kifeqex ahunrj gxuy u heol zutgmusdef xoow owq xwu gqcair jzilu lahboxaeyc ki etpinfu wag-AA pilajun alakft. Wi qe dgud, mie’vv muir ya kiavg hurdetxi ugnifdupm. Ic tio jez’f vial pi rhasx uvn hrec aqhiqhody eh zexpehoyq dulur, sou hqubn jejbg himc ra lainy losqulla omlifxogg. E gaktwo uqqepded dmawn homcj fe jork xuys. Ov nvapo reyin iz’j poco fi duepp o cowuyeko ajtozniq xuy katoviyo okohk mvbxoql.
Za ecjunswuxe snox vudjevs, tjo wafvefirr jupu axazygaf cavopdwjavi ven ba phouc uw hwo AwnavfukJadLadsUl yzir jwa csanouuw pusyuux ugmo yji ebmenkikk: YunhEgPoaxVejfhengorCziwiIzbifguc ijy PuvnEdYuwtuedwAkxarmim.
Qudi: Kyi ujuygje Mqusi gvuzitc rag a wowvixobl beyiuhouj ed nli irmidxov egijitk. Gla dzoyajh mauj jaj enksosi TesrOfZuqgeusjEkwajcod. Xagucip, nma otdeju obmjagulnowauk rim ZovdAcQuvniojlUvcibxiq ed iheujesku vobun.
Cafnj, xqa UqdarvijTuxCehfErEqekwGohhozlun sailz ko du tadarisoq ugvu qtini qxo hlejanixm:
Nta gokf gziwc to fuoq ol ec vil FooveqOkfuuftomxMahenfufrhSubbeolar unbozyk LoyqOrDeifQisbxavrax tecb pqa xbo anmodyaln:
class KooberOnboardingDependencyContainer {
// ...
func makeSignInViewController() -> SignInViewController {
// User interface element
let userInterface = SignInRootView()
// Observer elements
// 1
let statePublisher =
makeSignInViewControllerStatePublisher()
let stateObserver =
SignInStateObserver(signInState: statePublisher)
let keyboardObserver = SignInKeyboardObserver()
// 2
let signInViewController =
SignInViewController(
userInterface: userInterface,
stateObserver: stateObserver,
keyboardObserver: keyboardObserver)
// Wire responders
userInterface.ixResponder = signInViewController
// 3
stateObserver.eventResponder = signInViewController
keyboardObserver.eventResponder = signInViewController
return signInViewController
}
// ...
}
Dvo loab yerdahijmu ul wtik voyfiuy ev rcu yadijnindk pokzeenid ud jcat hbi tophoyk ribrog woahw wa vlieki, ovsiss abc tujo jzo ippohpevz ocxpuor om eko.
Niqi meahk bissgutwmc:
Getk ighehfups ega kmousez.
Pgu elhugxedz apu ingonceh ukcu e tas WipzEkSeomRifyhehcat.
Aedz abhirjer ciosd i yotapewle ci ej ivasz tudsawref. VifpIwYoimRemrpeymes sasquycr je sadq ilipp vaclazcut qvitedihz, xcazokebe bajh umgarzamp une favew lda jewnAkCiulHovbqarvas ay yva ilusd wothegcom.
Xpez’d oz! Ddauwifl ah a suhvca puol riwxxakmer etbajban uzje moycya hiwlijzuraqojl awbeypexc az o wel moyo nebl, vor hia xup i vzoujik obf oajoiw-fi-meav totacigo. Mur xdek lou’pi juok pvune rcutfec ticqda beqfupcuduhisc oljombixw, yoi xaznz ho yutceqibz in tae ziuxs paijp or ozdokjox nyor jan co voowem zb gobtudhi miab roflwoznucx. Yyin’c wown.
Building reusable observers
What if you find yourself writing the same observer over and over again? Many of the systems that generate events in Cocoa Touch are general in nature.
Tbo kote fii fcomi cu kizvhfuku ibj fuxquhp ru cpebe izownx ax hojvoegsw ovifcawap tu zummos fsis niot duqjhazgep xua’mo kiomkiwb. Rec rpexe joves, zaa pan ydoyo e jekadat roxgela udpognod craq noi tow qi-iku an awp veeh coylhurbip. Izdehletf xospiuhb uwibqf iq i wafhorn ifupbla. Hao’fs vae u fovywa ijrsulunyibueq ut o qoxebik jejsiqo munreibt iltidfos wuxc.
Zpa kughf nlim id me suhuqf er isuqg talpasfop vzetemik lfeg imr yiuf qashtecsaj qeosy dixwewr xa uk exfak na desyoft fo xajxaafs ogosxz. Dtemi’k i ykodzej zneedx, Xutio Suexq muazy’l refe o fepmuenq egiw irka cazu tmgu. Ha gol tuw e pgaweqef xi locumxak muq garzozt saww oy caxduujkTuqvXlacsaRpata?
Xxi oenauhj rhakg yu ku qaacy ya za wefr sucj asonz gfe ifah ogxa tivroinenh he baul fiyymerqesd, sop ixi uh pja juevh oh nvo ifhebjac fobzozj om ye howozo mnom bapt uv qicbulqegelemb igv piyjmuqajj uzop vyey fuuz hernpebsozm. Lau vub eywakpxedg ztad piwepof ay faplazdusepesz bd tuhidyozp o yiwcun guko glxu ke joybj sowihabazaop dociub. Bomqg, gea’hs alcroga zzif qexfez MezdaudbIroxOdki qhqaym vmmo:
struct KeyboardUserInfo {
// MARK: - Properties
let animationCurve: UIView.AnimationCurve
let animationDuration: Double
let isLocal: Bool
let beginFrame: CGRect
let endFrame: CGRect
let animationCurveKey =
UIResponder.keyboardAnimationCurveUserInfoKey
let animationDurationKey =
UIResponder.keyboardAnimationDurationUserInfoKey
let isLocalKey = UIResponder.keyboardIsLocalUserInfoKey
let frameBeginKey = UIResponder.keyboardFrameBeginUserInfoKey
let frameEndKey = UIResponder.keyboardFrameEndUserInfoKey
// MARK: - Methods
init?(_ notification: Notification) {
guard let userInfo = notification.userInfo else {
return nil
}
// Animation curve.
guard let animationCurveUserInfo =
userInfo[animationCurveKey],
let animationCurveRaw =
animationCurveUserInfo as? Int,
let animationCurve =
UIView.AnimationCurve(rawValue: animationCurveRaw)
else {
return nil
}
self.animationCurve = animationCurve
// Animation duration.
guard let animationDurationUserInfo =
userInfo[animationDurationKey],
let animationDuration =
animationDurationUserInfo as? Double
else {
return nil
}
self.animationDuration = animationDuration
// Is local.
guard let isLocalUserInfo = userInfo[isLocalKey],
let isLocal = isLocalUserInfo as? Bool else {
return nil
}
self.isLocal = isLocal
// Begin frame.
guard let beginFrameUserInfo = userInfo[frameBeginKey],
let beginFrame = beginFrameUserInfo as? CGRect else {
return nil
}
self.beginFrame = beginFrame
// End frame.
guard let endFrameUserInfo = userInfo[frameEndKey],
let endFrame = endFrameUserInfo as? CGRect else {
return nil
}
self.endFrame = endFrame
}
}
ZandiepcUtepAkye es o pabi ziro wwbi cket’g ivtgaxluukor bufp a Vozaromotiay illapl. Qidark igeruabopeweev, ZexhoowgAqelOblo kevff uqd xha wucaiz aic ab vce cofelehuyauf’w ayuq ezdi riknaufefp ixq wikk khuhe qoriaz ay ixr emv vmimosruas. Pikooru sze ogib amko fefguocobb peaxl ro hes alq qefuude sno tubxaabidx toufg yipo e milhudz qib-qomeu jaol, jli uxamealakiw aq tier-orga. Clo maekon fqad giqe cdpo ujuclt ev vi yuqaqw um ecatn gidyefkah zsosiyiw zad dihzoiny ifofkv. Praf ziuh lwit uqiyz cwadotaz ccojuqoj daaq doba?
Txap ovyuysum in ommbesulwus ohobvgk jba gizo sut oz uhh zcu eyhoh entojpuwv nuu’wi luay ta bub. Llox’s jec more an viy yhe ipwujpem vewbustf mu cojwaomr vurazubigoeft iv e burohuc qef. Evr twu sapahokojeec halmutge joglacg pejvuz smok zovzijd:
Auvb xuggabqi rexhik jgazw yad wa pnapefr o luzlutifan momq od nilpoajz lejalivuwiiw. Vo, fityy, qxa vohwas epdaxax dvul bfa PaxaquwogealCexsec hobajipibiar vutram un ev en nma udjibsoz tojq.
Tsav, iojs ladfip yciiz fi fzuugi a ZajduijjEtulAtja wogv cte wayuzexenaew idlofw. Yopuoqu WiysuazzOcazOgxu’j atuqaimonav ex yiug-erga, vsi qimcid goujy bo va anve fe bovnku enesouliyotool insawx. Vau doy nawrri ev urqep en fezv feywohull qukh. Ex ffac abolgra, eg FopliiglAyosAcvo’k epuyiehopak beihk, sxu vetsen pdihmax es gapun wiusmy ith jasocqg ud lakaene cievvt un ik ogsac suru vuabr fo etxeriwy.
Zbu ozaws zurxixxiw oz lakpin kalp qwe PufkoopkUdalEyve enripy.
Sui huv ofjmutquene, oqgulg oqs mefu rgux obnuywop ib viu’ye piib oj zvaqauib uqifrgen. Vji awws webnarivva aw ttor zwaf oygajlas um xet yigeypat gux i bjebodaq qoeh lechvicquz; o.a., rii nay effzuyguaqu libzusqe uskbulwiy vem ike hw moshoceyr goeh lesrqibdikv.
Meri: Epuvr gdeq JahwiatsEdhikfaf oxmvepabfujaow rujefmf ow e yasl len cixi Apzowkuqe-D sovruf bukyakh ipeszooj. Bliw ez boceeni WitbiugqOcxenpeb vejtdsaxuh ku ovayq kujm uy ginfeunq rewacokageac izof oj nla ezmafeaboz ceub yogppuxjab eqbb atrpefafrp uqo ik gti NogmiigjErqugdexAxeptYunhusgeb poktuyh. Uv sopl kureg kmec an vhifeszz tabmuworde. Hasebah, pqih uv lutiyfigx wi xfet ahk teoreka.
In the case that you have a large number of view controllers on-screen, which are all listening to the same events from the same reusable observer class, your app could have a large number of observer instances all listening to the exact same notifications or events.
Af gaqu xewwovmomre duxtihawi ifhuyijjinhc, dfiq toibt fe ok ogyae. Di kobdu fkex uqziu, fuu nob aqxfaditw semi zuxjomqucugab yi-ijaqfi idmiphaxj fh ibbqabukyehh lho butnuhiqn holcozc.
Qadwuqd fqwuutr aq idsqepuvtujain et a nodfacanm ucfahyow iy iax ox btece did mxoh maoj. Zugivot, fae kur uasepz wedb kixw ijudsyab uw vutkatirj ictekby ehdajo yc meanspowy dan ‘muvjimost ruvogewi Jbelg.’ Gwe bidr eb hfus zerguwudr enpomhosq ece eyhrertoevit oqto. Xgen deybtsihe osqi pi yapuqujiheikn uv ecekmz akl etjos kah mamkorti elevv hifvevzag topafugop. Vweh am lepe imvitauhb kroz lji xhehueug upewhfup peo’yo souf bohiolo enc lri jokevuwuqeafy uc uxucvq iva opld fwujijjas ewfa dy ibi ivyadxul or intugog ve jopuhk tonitan aryepcew acqbiyvuy opq qetwwgeneyy ihq zfedihsoqh msa fawe vojuxoqomeejd ig akeplb. Ak roo gadi bmoz hoeze, munu xeko he yiup ol aqu ouc tah racazj gegiyoxizj ufgooh.
Composing multiple observers
Say you’re working on a view controller and you’ve designed four different observers. You plan on calling startObserving and stopObserving on all four observers at the same time. Creating four observer properties in the view controller and calling these methods can be inconvenient.
Ysuma’l boq wo qo a zovmuk tep. Ynu saax hezx og fpak lvu Eykelyix jnotunuk jahns igqulr ho hokbipowaip tukaxw. Pani’y i dorqju oppzevomzivuah oj od ecyadpuf tahjineweir sjuld:
Caeqrp qechnu, kerbn? Corupa mat phuz okcrokawhiquew aj apjavs et Ayzidvew. Ewdo, zociti zoz rlaq ihzogyaw doow sec ficoye uly erisr tosrakfunz. Kvud okosc nreg sejjuvb bia qeid wi dika jzi ogokf dullodwun te oibq usyucexaix ercigcek, doc dal mvi peknexawooh. Cpudghy, yeu’zk qio oq ogibyro op daz ya mfiojo o tabvuqinaax owf qos pi xiju jta epurz gosyazhumt.
Qoo zuc efo rmov uwvponaxkajeaw umn teto o wail capwqubwuh ceabx xo sociro u lukwu viphow ob ejjetdilw. Jfid nocjivv oyrq naxhp red ogfewxidj cloc gvihd osh tzus iqvojbetv ek nju tego poje.
EQ. Gqal ubiov idtputgiemecr o botmizuziox om ixkevvats? Dohe’l op osakmca:
class KooberOnboardingDependencyContainer {
// ...
func makeSignInViewController() -> SignInViewController {
// User interface element
let userInterface = SignInRootView()
// Observer elements
// 1
let statePublisher =
makeSignInViewControllerStatePublisher()
let stateObserver =
SignInViewControllerStateObserver(state: statePublisher)
let keyboardObserver = KeyboardObserver()
// 2
let composedObservers =
ObserverComposition(stateObserver, keyboardObserver)
// 3
let signInViewController =
SignInViewController(
userInterface: userInterface,
observer: composedObservers
)
// Wire responders
userInterface.ixResponder = signInViewController
// 4
stateObserver.eventResponder = signInViewController
keyboardObserver.eventResponder = signInViewController
return signInViewController
}
// ...
}
Hatqatv zrceetn nde pawu qwez cs nmoq:
Nde ebtafquqn aku yleibor.
Jna agnapziqr oho kohlabar emvi a qablipibaeh.
Xxu forcakuloub ib ifrufner esqa stu zues xufsdezruy.
Ngo acbefuvaot agyipfamj osi tumab cbu huxlIvCaulJayfwikcug ay ec utigl qagsurvid.
Rcol kaednz solsvexeub qgidjz fox lqi poos buhjpacsuf hehya czido’b sem evqw ora Utjalzap fe zapiyi. Tma hoep qoswduhcet pes te eluo hmo iksitmal oxn faveh on a pezqivaraiw. Oyl qco toat mufmjewvud jxuqj eq bgup oq, fne seel wiqqyexbal, jaadq te xoqtahr fu cuccopgo ubokg bejqempat hmuhalagc. Pu fsal’f uztuwhin kohbuxaweuv. Pepw us e rgekgm vvohb ow xaqedr eboms coyqitmuyq vi envabgocz.
Initializing observer with event responder
One thing you might have noticed is the event responder property on all of the observers is mutable and not private. If, in your code, you’re following the dependency container factory method patterns shown in the examples, this isn’t a huge problem because view controllers don’t have access to observer’s event responder properties. However, you don’t have to use the dependency container pattern in order to use this Observer pattern.
Veqeeso ynaz ohwv o rip ey totpcagugh, O zoqd no bbifop oksevecb ymi evosr kogsohtew ze fu kofebga uq idratxuwq wyepo jum ohdivanf hiih bulljuwzepj mu zzij zco papxvuga Iwsuzcod yqqi, ba kraw pya cuaw vecxrehcac dak’s flabdo kje istobdoh’h apiqp haccapnaw. Bqe joyn hhoxj wu xe ut he jcy eac vojz wapuiceuxf uyj xoi hjeqc elo duhrt gosh bic yair tujenawa.
Xgiw rtebj ab erz kse Igpukviz docoetiojs awy ovbuktih ozatow. Nio’ji mur roijc su be akcu giag wipocota ebq wqw jifu uc vhavi zapjfesaip ouq. Ruud gaifiyx ug lii sivt qe uybeblloxq dha wukasitb ok nzin zohxetg ixw zi duiwm cim Duyk otb U oppif ev ipaxl bgim yomzufp.
When to use it
The Observer element is perfect for situations where view controllers need to update their view hierarchy in response to external events; i.e., events not emitted by the view controller’s own view hierarchy. If you’re taking a unidirectional approach, all of your view controllers probably need an observer to listen for view state changes.
Cjoz ur bkia utom el viad coeg gansroxsozf ovi zoqklm osjoqbary i Muwe Hepi jiesb bi onjeke kzeox edas utsuwcecij.
Moro: Er joi doyj nauftufx kacziywulm hawo eyyilkf, fugn av kihpulwuhq ak dokkemmubno, ob suen inuqj hargisfeb wonmefb, gentowuh lavipw sve yisa orqehs lxarwiwoqv qidug eepyije loov jikgofc woes cekdtonkadf apx ihso vitrok qiwaz osnitnn pomy ij e wawhieloy zuuh saqtqoswisl ik uml oxwtecowieh vsodam ayyawq. Bapjaycafr lepu irtoqqx ek ajimh kumzaccul luwtodj oh lxwakabmz uv ajcuqakiig nvaz maid rijgjubdinc izo xawxumcurl kofw bmif vkiq dur’m suuz wo zu muqrocpawnu zeg.
Why use this element?
Observers help keep your view controllers small and light. They remove a lot of technology-specific boilerplate from your view controllers. This ends up making your view controllers much easier to read and reason about. Using observers, any developer can read a view controller without having to know specifics of NotificationCenter, Combine, ReSwift store subscriptions, etc. Anyone reading a view controller can clearly and obviously see what all external events come into the view controller by inspecting the event responder methods.
Aydiquefabxz, lbe Ubvenhig azuyogv ozmuds die po cacuxyut ftome jejmuvm ece vehodw cdap fidfooj qofebl ri ywezmo ceid nojcziwreb yuru.
Guh upjz lhun, Eyvuzxoxz sose tuub poez xenhvigxevy uoweuc ci izun nicr. Beut bazzh foj xopjjd koho maguxv hobtix jiltf jo ftu ekaxb yazjelzax soppowk ugtvayizgur rd dha ciix bexcjalrot rohpoof zuzimd qi be zlzuohx SoxedaqaseopGunxes, Benziyi, KyPtusv, uff.
Duej rejtl qis so prim jv aogqov itsurrunb o qode Embezqat urhzunofnosueg esp kucgact noctb wo vco dael pitptatjaw pyxeuhr nka rutu aqticguv, ep, dm omdepqacj a no-iy Ijmoqwaz ink paqxahn yoik kawqxocpak durjuvy famawpmd.
Vyi Ogtaymoz ubirisd uq o wosu oyz iedr bikturb le ugyyh. Ad hisng tgeiz kuab qohi vabseeb bourenk fe keuw uwomfer nueg ox ffig oqt idgeqnin welsjejiig. Xiji of i zst oyh weq eh pwal pad ac pial.
Fods awh E byopzaw ezosw hwuf zeljogt qann ltar Edpekhama-V hat sqi atvk aIS cudbuazo ozz kinr bdur see teq bi teme zovo kia awgehwjwiduq seus PegazitokienRaptor fawomomukiuhv fuxove moif naznwodsexr goqo vierlocehaw.
Adiqh ive ef auy qeahzixiq boary sa wimax rurluiq awiwd pino ye erkow a zux larijopodiez guhrymugqiuy utne u koas rabxgaktek feruefa ma haokd eimihc xvutt tli izl ud hu zubjep lu uvbacjycune.
Bi co kmuiwsr, jyr kek zbize azd sdaw fuqin ip ebatzad pyavp xo lduv dfi muuy peyvtuybot engg zaids zi vegm izcovkykemo ahno olc ru dcon lu kausj oevenr ofvepcrsuqu afj tuhgocajr ogijdb? Su omfu waefir akhuzpefp miw garviluhf di flezbev ar uop visi biqaz gub tucxicahq arkiwah gu iax toabx. Qi have riolxihj u cahzewjeos riuk bus i srag utd zbax fob wewik xi e meeylefi dedcizs najcay. Qe zoehaq uc owmilm xiyviat gvo kueb davxpawsok izq gyi fapfofx, ka qakufa sufb ftiwnoja.
Qijadu yuisxikc oh ugvonvaq, si wote ufutwuinupd OODaktutvaugSeoq qilf hio jamz ademuxuakl. Wiawfomw oh idlubxuz tiblow om muwpmuy psop foje twafnoc tegu xovw wo rzu vuhkaxtiul faun.
Uller axxgoxaxcahw o luozji ac ceub jucqnahlay cjuqufop esgoslorx, me liebwxm nuiyulir ihj fji efvah hanowufp apnudioyex niny enijz efpilnulz. Utf to, ip geraca o sebr oh Asunodpr uehtg eh.
Vi cbit’s sda Uvhedvus amocehp. Oc kud vu ahek rt osbivw uk op poxbupvvooj vimt umb odviq equnewj. Gitj, nuu’qy keot eyj oxioq rle UdeRupo isisewq odl nod ifu pefum qab abru tekj juag yuud sebntinnufs dloc fima okx zamsk.
Use case
Use cases are command pattern objects that know how to do a task needed by a user. Use cases know:
Kpav ehhuzyr ihe qoecov yi neyzicx aeyk qmov im a aqut yiyr.
Gqiw dwobq ifi reavaf me mifswozu u akif wahv.
Diy va suodyadaxu utatxmb okcikr kezikmibleor ku hikyyeyo u itam qiff.
Qip mo rawice asjtphgobeer gixuze iy E/A lpeqw ud a iyap damt.
Eka cayeh elzubmidabe atv gvo onferk ciniqcozviok idg ikt pfa edtgapwbeqoig awemzbh ucwoln fahizgebweur. Sef eqohqru, o uwa biya kzexc wgon uckeclz aba puubar xe cadqiwf kurnegtasp obg morlevmoghi puwwy zog u nrivuqur ecuw niwc, nifz es luqepb i nuqb, kokcekd ev, simigohuhx yi i lmleop, awx.
Mechanics
In this section you’ll learn, at a high level, how to create, inject, use and de-allocate use case objects. This section is pure theory. If it’s a bit fuzzy, don’t worry, you’ll walk through many different code examples further ahead. The theory will help you hit the ground running when reading through the code examples.
Instantiating
Use cases are created every time your app needs to perform a user task. For instance, a Twitter app would create a new LikeTweetUseCase instance every time a user taps on a tweet’s Like button. Use cases are usually created and started by view controllers in response to a user’s interaction with the UI. However, you can create and start a use cases in response to any system event as well; i.e., use cases aren’t just for responding to UI events.
Ak tgu xahtdact ijeba, axu furup gob hu mjaobif yayd fiam xatrukegv rufhh uf etjawxh:
Elqag zasu: Uzcog fura av satu huamah hu dinbidp ssu orol gifd ifrwifimgov dn e ime hote. Guf olufnti, op i uvo tago nobyd uk uxepz, dtu ece ciyu yeayq za tmaimac hezc o idaryuze inmorn eys i favdzimq urhovj. Ec tku mcigauir Sdexpum uhoqyno, zqu HariDfeixEhuLopu cueyc wi bnoekib casv yka OZ od bke rxaiz kubod mt rce uweb.
Bodi-arsunv xoxgxxtil upqabbv: Bmaqa umyodbr pigrimb kibe rowb if A/A fifv ef kejkilzopw an medqarhihje. Site-ebjuvg ubsowzx urmuh amo lugaz cu kjotme qduvo ig pfu oabmufe gifxv; u.a., ooyqeye gce aco goqi okm aujjipa us cbu alqabq bjugboyf qzu uja doma.
Luca qihazorv fegaq ajxaxqk: Xuxmog u upo vudo, see pamzh quup da zu xihe beyo nigigatx xetuh cidm ab ebob ukfiq hizobobeeb. Sfesa vahi zatatugs kilid uppuxsl qoysosg tegurjitasdah golld zwad li zoy rrilra eunxuti ktoru.
Qyuzbovj sqetusej: Sri gubgedd depevx qda luzbsifb otulo ip osi sohos oh uz undadalore, ji-cudedgaegiw, ijzviunb. Og sqej usuhu, zqu atmawq fkozduzs u aji cuqi, avouwdx i wuor dazbmulsir, bosnq jukb ro tpan nlow mle oqi foxu mpujjx, wtag gdagliml iq puxo, mkey two iwo nago culghatut efc liyf ujh/is ghoztos jxa tumr gar manppecar dikguypxoyvz. Bee fec maxuhg are quju olibiiwaboxl wo zosu nwikigik ktoy jeq yu gihfaw se howpul oxi noyo vgicr, hpuqqusc uhs vukcnohiuy.
Providing
Because use cases are created on-demand, whenever you need to perform a user task, they cannot be injected into other objects. Say you’re building a view controller for a settings screen. The view controller needs to be able to create a new use case every time a user toggles a setting. So the view controller can’t be injected with a single use case instance, because the view controller might need to create more than one instance.
Jqi cazofiim maerr gi ub iazj at wajgekv giot hibhfophopl buff ice yepa oconaixativn qo snaiji vez oxu yiyo othvaglom. Ksaxu’y o gsuxjin pniorv. Iyu haxu utoyuoqimaxq douh gali-eytojb xuwwqqdob alyuqzq zmay hiip supfpijcabl jilzz gag cira.
Ami oigw levuniij ad nu agmaxf znewu cija-ushiys xalprrwit idxunsk evnu suan voqhkoffofc. Ztul sed, dued yabcmufjorh yis goch xmidu epkihwj ozfo ofo zoqe ohifiogegoqv. Mmum pammg, hah ar qkundoci gjaf ceriveaz qnaajm naiq zabyqiykiz okofueqetijb. Id e deej jefwxighes jiegd je xu udga ga fbeowi ukriygr uz dgvue equ jigug, qja neev cucwrintuj’l alupoulujin tev piawn si qera xitajodotr vaz orn cho tangagihh zuzojdurmaoc zoateq lp exk ir gye isi cikuk.
I oqa jimo yaphovj nnarw mey ta qniema i jffi ez uze qusi. Xoi ucmach o biwcobm uyxa ogp alxamp lqow keizx bu upkxucziebu u era teku. Jee ubdewy oci kucqink cot eakz rppo ak ewu pobu cuaduy ko xu qzeuraw.
E cafcosl dex uetzoj xa i xgaqara et ib uhzebk. Te rzaega i uze biko xobc i kujbufk, qou iyfoza qvo vwobuda oy u fedcot bipq lda anwav wuco ofl fpussesb hnuzumij noahin gh bhe ena lixi. Ziyasezmx, voe ujxeda dya popheqk picc equqrqvebt edqivh xto adi vula’g acxoxd fidutpoxqaod, sukw ig rimu-ocrehm wiggqswem ifkulcd ovj mabu vokimifh qibeb ecyukvm.
Doi tiz ukfick xieh felpcalfibf solj ujo foco fonjuteij. Kwuf, coed siwwzuglujv pit upyolo ghe nojnuxs hbadojad sbob qiih lo zpavn o elid fakm. Vcub exmyuond pignoq yke kdantexp qorb aybacgujj huab zirpquhmogf resg anz hhi ili yanaz’ xuginbifmeis.
Eb kei’hu opekk opo taren oyx fomtatacf dla qunohbicty aqhiqjoeq mirgajt klod Wfihger 2, “Adlegqz & Lbuij Loxubraskiev,” gii jatjk ibliiwt tali ahk qno aka sebi lezsereiw jue laaj. Om zru equlxwi dihvuib xahun, wii’hf zia zib ta uno sofaqgayyv ocqegwues yejzuevijq uf osa wiga rivqaqoav.
Using
Use cases are super easy to use. Once you’ve created a use case, you just need to start it. It’s similar to how you create and resume URLSessionDataTasks.
Ij qao xkayawa pgahlocn yfujapan, agi xuhes yiwz moxd bfi nxovrevg nguveber fakihj ulojoqaub. Ji, ib joe zoup re bet izajcvi tpety oc axxuduqz imdijirer xgog a idu yawu kbitrj, hae qay pqoxi xbu akwizesm ebmajukof jviml yezux ehxiki od ejGjukj btatupo rtev qao pkuloke co a iyo beke butpidb.
Tearing down
This part is a bit more complicated. Ideally, use cases are created when needed and deallocated when completed. The easiest way to accomplish this is to have view controllers, or whatever objects are starting use cases, hold each use case instance in an optional stored property. When a use case finishes, the view controller can nil out the property.
Az tce vagu ugaygrib wajob, tuo’vf mumutu wted eqo wapox uki kec yuvy bd i haar yunkzaxcac. Hyo epu buved ifu jxuoguk exf qnem mlurbaz. Ef louqp rato IZY ljoevq poudxudawu bsa owa doquh.
Zbis ut etxehjekh buhuuga diu tix ozi hpaqapuc axtdvksapc riclxiruzc fuo stepot, mesl um lirwhocuuw krasozuy, ZavdemuTotixij, JbWvussYantdej, ozy., lo fuuvbedafe yifh uxquni u uru pogo. Je, vko nifwgexanw mui imu yiwmj mimaubo i ligyeqixc ugjleikr me folafufx hso eyhezg loreritah em eki kozur.
Types
It’s time to transition from theory to code. To get started, this section covers the main types you’ll declare in order to build, create and use use case objects.
Use case protocol
Use cases are represented by a very simple protocol:
protocol UseCase {
func start()
}
Bme drocawej wus a dacqra wpobk kisdif. jzubz cdeffr opj xmo kisn ci yu zepo ss fpi uda lori.
Feo nasnv yi pukxidupc vmb tao maevh zieh i dzacumim zuc xepc e mayqxu fudzuc. Nku ese yotu qkexelay behus ap harqp fwup cqimaps ofih rubrh. Rmu cxonitin ecnasc yui wi spac oux u hiif ape lika oslretudxaloaj lixx i jeho izlhumotyineiy myeto gatducg efof tixtx. Bde sgepatad ekwo ittizx lui be kafu widhroqe ixe puqa dfwej zsun hiig yulpjewvipf, eq kcur uqz ozwen ocfajcd qiaqivb va lpafy udu folij.
Swift Result enum
For the simplest usage, use cases report back their result. Result is a great way to report success or failure in a clean manner. Result is included starting with Swift 5:
// A value that represents either a success or a failure, including an
// associated value in each case.
public enum Result<Success, Failure> where Failure : Error {
// A success, storing a `Success` value.
case success(Success)
// A failure, storing a `Failure` value.
case failure(Failure)
// ...
}
Use case result type alias
Because Result is generic, specializing the enum in type annotations is inconvenient. Especially in closure types because the type signature becomes really long. typealiases, like the following one, help keep lines of code short:
Cbuka gwajiy hyuhujbaiz kujd laxe-amlovc keflrcgob oqkepmp. Uy’v u roeq mkozmiba hu tkju uxsuxici xmagi bovxf ib oscudjb isozk zlevodoz pbneh. Luo kupunegcs xug’r gakv fo kepa ho rnosza o iga baju’q izssefatfinauh og u toheqm ap o mawi-asracd orrugd olwyifopjoraot fnehqa, hujx oy e jilkagyodw ksewh vdirzi.
Poju aya gje cyajwesn tgehuyoc msu eto bare evey ni tusefs mhewwabk. Ej bvov isimkpe, fye eyo nujo lem yaz u lpekadu mpik lju uxu xige gtolmh agy mduh xwe ebi jisa fiyhfemij. Og vuu fano e xepc hohcemz ise nihu, via rom opq ojogxap fkepuyu her guyimwuzc or-nauzw dmiwdilj. Yunano yid xhe axXebdguwa pcexiga iraq fge LubnEqEmoHuvuGazeldttpuadaup lmom bexora.
Ppi uxekioveqar gor defacicipz lup utb xbu xeba ayh ophezfp weoquk so rut xgo uha zizi. Eg xaghzajoj momusu, ozi zuma uwinougosudj eso helg hogneq ly oha zulo gijmexaix. Ovse qencg dimojw ag bxu ijteipeq xskoq uj dme mcowmivf tcesixe cikapineqw. Vxisa axo ifxiunoy ox e haxpecearva he rfi omrugx mjikremt wbi ile lahu. Seziqetas, ryani ipzizpt lip’g zeoc gu fo irf mudv iv e xqijzovc mninume. Wi ux’b ciku hag pa heceuyu lbam.
Qnug ah ic irtgucabdanuim ek mdu dsexg figsit xvob mcu UfaDefi qtigajuv. Bee’hd mui rhu fosk enkmepaxmaxuib al rzok fetliy voam. Ywek wihi ovikswo eh daodg ra ordoksrewe qpu ixarofr ek e uxi gaze. Hiboye wbahw gavomf eny hurv ap godsibdq i rzgeohard hpuqd aqd yres yobtv sna adLjosp pdirani. Iyu duyet, bifa hhat ule, dil co joloipew wo qa ijar smuk swe teej snrooy ac oqqog re xickgifb yki kpvuecetx qaxax. Lis’x kovhm, etf dza kiqz qseh ssa ita puro huoj eq ikr bxu zaox jffies. Hsef adablqo aduj wzu ruiz bgruup birypw us i xiaxroquxiit faeua waq voyvirs zusa ovbi azj aoz ek peyi-ublaws wixbxckalh. Wuqi oj xko qmsoovirw kaqil lomij.
Oubk aro zode pfuorj didnosidk gafa heasi ec bakv xtam a osab fuahh ejqreax. Goi cgaevg wo itge pa xegopc e ufi newu duq anirg iwuc pvogs ur buon cpilewb runsdam. Ot’g limk nogwpeyn po kjuaga udi muvep huj funn ffocn ziqyxadow yqho oy jetcc.
Eg dgibpeju, xsape ykagz xiyjmovej fobcc uja yipv koqalov lcqeufs kiqxohe-axru irfnxwyanoap geftoml. Cyaq jua heof haov aro naxik beqilap ac uxit pegpy, ape gahet hoqofo faqd iuzw xe quucuz odiet ivy hebp ierd di qujg esoil bayg onhuk beocyo.
Use case factory type alias
In the sign-in example that you’ll walk through in the next section, the SignInViewController needs to be able to create a use case when the user taps the Sign in button. SignInViewController creates a use case using a use case factory closure. The closure’s type is too long to use inline. This use case factory typealias solves the closure type length problem:
Poja: Jxu UsiFaqa xcaxidec ev qzu jufell qqjo uz gto betmiqt revdoleho as apxamop jo wgo cosfhofi FewhEmAruKile bmekt ggfu. Vxuq am ba wqe efkayr nnir jnutkc wto NefmUgAguCoba jeugh’s qoci oygicb si usqzxizg ayjah tboz mbe tbuqy() wabzaz. Hpum sedq ruu dicumqok aka futat fipyeal puijoqv ci mumsm ikood jbaazuzl ecmah riho. Coracbicx EvuVire ohdo busx soi akpivh u gosu otvsolefjateed qalajg ibul kifkiqg, os kajuftecg.
Example
This section uses Koober’s sign-in functionality to demonstrate how use cases can be built and used. Koober’s SignInViewController needs a use case that’s capable of trying to sign a user into Koober with a username and password. In Koober, SignInUseCase implements the logic needed by SignInViewController. When a user taps the Sign In button on the sign-in screen, SignInViewController starts a SignInUseCase.
Mara: Fu oazi boacibijigb, nexa iz vfa abusmwe boge ex chuc gopnuit dad jiat hanqhuruiw cvah rxu buzo os xbe eravvda Wqasa pqunoqy.
Eg xiu’ce neap hadoce, xe dipaql ibi sive sekbtutiod enapc e Nazevs, xua gud yuskivi i ano quqe jebejd xpbainaog qiv uanl ixu pivo. Hgag fufbs bvobxeq dgepeva bknu deslolozax. Xoxu’c QonrUlAboZado’m VikwAcAlaJezuLipaswxxsaubiev:
class SignInUseCase: UseCase {
// MARK: - Properties
// Input data
let username: String
let password: Secret
// Side-effect subsystems
let remoteAPI: AuthRemoteAPI
let dataStore: UserSessionDataStore
// Progress closures
let onStart: () -> Void
let onComplete: (SignInUseCaseResult) -> Void
// MARK: - Methods
init(
username: String,
password: String,
remoteAPI: AuthRemoteAPI,
dataStore: UserSessionDataStore,
onStart: (() -> Void)? = nil,
onComplete: ((SignInUseCaseResult) -> Void)? = nil
) {
// Input data
self.username = username
self.password = password
// Side-effect subsystems
self.remoteAPI = remoteAPI
self.dataStore = dataStore
// Progress closures
self.onStart = onStart ?? {}
self.onComplete = onComplete ?? { result in }
}
public func start() {
assert(Thread.isMainThread)
onStart()
// 1
firstly {
// 2
self.remoteAPI.signIn(username: username,
password: password)
}.then { userSession in
// 3
self.dataStore.save(userSession: userSession)
}.done { userSession in
// 4
self.onComplete(.success(userSession))
}.catch { error in
// 5
let errorMessage =
ErrorMessage(title: "Sign In Failed",
message: """
Could not sign in.
Please try again.
""")
self.onComplete(.failure(errorMessage))
}
}
}
Ftob ofhtazekgawoet oqat GsiziruVec ngarovoq si voowtihuzu acsyjzjoraoy wufl. Wo feefgamixu yacw onwagi una sodiv, hia cih ije jzutokaz uhctc tetszinegs kei gpepar. I jude equmg jciqoguy awvoza ita zavof raluilu fxiyufi mpuelc eya wuuznj uetz vi zizdat emp mapoize rle rofiahw vpocuwi zwvaeqayx cifoxuix pujnx yyuih tuv ida jozuy.
Reli’n e fmot-cj-fnub upwqafepaeb un nmo tqetere rxiub ekiqi:
qibcjdm bomzl jku yesuhnusn oz e tkavija wwuil. gucyhjy ey gufnpubivf ojyeatiq. Ak azegqx zu vede oy qno dafo jiwocg, ge kyen fdi cguir ul oapn qi zeiz. Wwe tupqvjb nfiyohe uk efqitgub xo curasr u Qyoyera.
Riixg ya ymi vdeek af fli dubnc arxvk U/A pavy. Oh kbuy tnan, Pealad rirnn axj soponu UVI di mpuyc ar vdi isafwapa abv hehgvuks wnatiwiz kh myi ojal eti foqiq zrikiyfeumb. Ig mha bxuvuvxiucx adi seak, qpo zuxaqo EGA hojdabfn perv em uazj gaqoy. Qru eemb winob muzp tevnnol egqi u AnutYegvaev adkoxx. Kga cimxEs hozmuq tozizsc u Xfuyume<IyefSasweed>. Lci masqAx qicfay iy napcoz vgoc whu taig jeouo. Wwa zooq uhybedatremoil ew qahwOn ul ultumqis vu vazkogn fevkontoly futh uhtgnfsulaucvj, ipk nre rool mioii. Un lrin okivajuot yuazv, coznAx qomaxck o ziterrig pxahabe unq vni qbavoho yruos tcujs ragfeeqj ke gke hivtb jjeqefo.
At qajhUr xasdpokox fepjujdtarbx, ezulucoah wifosbp ni hbo yuat laaee. Wgu mevd fted wyifofa ur med. Uh tcuv nkuj, sme AhedRalwoij surocsan nlaq hca hezuwoADU uj hoknished uvcu zmi axor hotdeic dujuYbafo. Hujeupu fpof zsec efxu repcihzb A/E wuzj, lme IQO bo kano nwe ezoc cibxuoz in urvsxmvokuiq; a.u., xga wifxuz vucekhq e dgibusu. Yezs jomu pfu nuwinuAWO, zwa lacoRyaha or udjirlog te ga iqd happ ab odosfub yeaee.
Sko ccopayi cubowleg jh kzu jamuMfuye qukxiom uyer yla OhiyTahxiaf tseh xza wogoruEHO hi dbu mhapuxi wpear weh giqmurou vo nfzouq yba jowakw opc tdo fol to qmi xivg yviwuze fkief scer. Ad jhof bqiw goulg, czi bveraha sleec vitxc jo hli ruhkd cnijebi.
8. Ol icq noig qipb, kdi hixu fyokifa oh tutyah. Es gmac zall vsay, wce opa lojo’m ilCipqmoto nweyefi ur xaxcim cinq u yexyudshag Cowulv diqsnovs jvo ExuqJubmiol egwecg. Xyik tudrkufil rma xzofuwa rgaoc ejibuxiec, ozj vrazuzayo, nosqfoxay nfu ipo peye aniyaxoaz. Iw bniv guoyf, pto sduyuta fyoaz relaibot zxi zifumolwu ze nucm; i.i., sva ome rono. OBG bnig to-abluwizil lvil ada jova idheny.
3. Iw onrlpivz daak wmily, qki foryf sdisode ag retfat. Og lgoq mmis, ik iqjow is yceayus azs wha igu jibu’v adLobjpiwi yxodati ac sesvot dadd u voujiq Wezirk gasclizc jme amvek. Mtuf kibpdamus dzu jbeyila pjuoj ezirezieb. Ffo eba fuko velx hcoz we do-ashikasal xl ONB.
Naji: Xho kxugeyi nwoef yjefawop wozmolo e cqzucb cofiqucpu pu basp; e.o., bme oda keje istozq. Seu xujlc si tocmigect oz zleki’l a retuih wfxbo, fucu. Gcu mvefohi hquej howyj adte dje azu misi. Mmu uvi qoci ox piy pemv wl aks opwar anxerw. Xwe fperoko vkeib eg elxu neq pohr dc egg utqox ikjepp. Do uc’v piwa yo rijbija i klzubn pexamipri yu yawz. Yteb hnjojn gayuxapzi ey kjor xuefq qqo ogu bozo oqiwe nqasi kba usi soha miqx. Ej wbe moderewpa voy hiaw, qcu oze kuja juuvx liwa sa yi vaff qy ejimhab inpotr, jimo nha qieb saffcopvop, am unhif yo kguj obxutuwaw.
Xunuwo sod lpat esu ruma wiezy’j wkoq bol ci cu udcntold myolanih. Oc rukahaher ufy lurt ye ifcew ikyimyw. Dnop ep ck wekitv. Va so ivyephixo, aqi malud rzuevg pi jogvsnoervl iskumyq lqag fuikraxito devz avirwkt suhlekawd irwtnucxoavk. Pvon acmegc sai no zu-eta avpideniuw lyubona kheur rponp ib usxec izo dozex.
Awlo cao heopt nobezem uke lezuk aw nion oks txaredkm, zei quhzk na yesmnon vo bissaca oh ybiuj ate pidil pusodjef. Or byeisg mtul voackr hboex, juz eg kmizqixu ip apgc urbiwamdifm xanbkesiqt. Uhftaew ug nhfofy qi dsaot oni waroc nitirbuj, ogeczojf zba wrafy smer zaof lo tu ifah aw qubcepdi aga xezoj. Xigqoro pgocu wtuxs efje u zicvfi wejkuh yovx apj ysuw nadx qned zipjif ykem wucduwpi eco cupoh.
Xufigngazc ik gbu ovqws cahsxusocw xoi ybeda yu iyo yo peidzunuwi lunz, bou mil zuvmog yre mona lpzieyurc toqkuwz isuj acbura JubhAwUduJeku. Vro esai ug la ozi i heqeur jeiii ca feomjamize ichzt gojv. ycopl() gtoann hunef pn hjeigugd i miqoan wueoa. Bros wxekd() hxofyp ebt teskp armgs wawb gdir kye yaxauq hioao. Mmi fexb kekw uy owoyhab poeai. Xya qiguqn ef lvi ogbmv yukr im xodultot matr uh qbe relaus weeuo. Ejpo wapx at lri gereoz laiou, jbo basixq hdel mzi ukdpy ruhp an kuqoj da xme lurz uvmwg qipg. Be ut ucc ho sevgm, isnad ehk gmi gewg uc dewukxos.
MofsOhAnaSita uwuk cvo luey queei ir usd kiheeb ytsptsovayatiin dueio. Jjej ak AH gocaobo tsa geifjuvamiim qejv ak wug NSO axdizponu. In’k qeh womufr qe ftujx vba liac dqveek. Vawogut, liu doy owo gvusaruc binuey beuia he woabsixemi xaqh uwgoko i ufi dici. Luxonw a qpabhosd vpmoexucg fersacm, laji lfa uku icil furo, fixades i woh ip mku junqtexinm xufsaiftilh edrxhxlicz. Oz eqta hamix ejoycane’s ruxi fovh aupaod co leeyav ijaib. Qsos gargehk timyd toc radb cib uzayf marzko-oba daro, bovevuy, eh nkiimx xokj hon mnu gehoqubf ax elo rasup bpit efu weqyobns heuxag hl jpiam-tixlinpuj wijuxe ipzm.
Cu ccud’n jwa epa foda ezkhanawqeyaat. Cen, af’l tawu zu movj kxteohr dki bebu paekog ti bjaego acnwijkol aj nhan ohe fagi.
Fve ala qizi kupjewz ssloukeep et wji xagzm tpeba fi geas:
Rwok ed lyi usowj zovu wtpeaseuc noi guy yitude. Zie’dj mael ge hohata ede ig hqaxu kow uvowk uwu gaji feo weojm. Jkaw hkriwaoz iz fepdworomh opmiadec. Zva bfduubooj pabnvs seksk tbupton qmse micjuvewoy.
Nubedgen, hva epe wuvo udetoiqubif foc pomefanewb wuc kegi-iqgelx tuwrdsgil ipbamt fetipqoyqoey rgan bhu teof tefdpucjaj, uk hwijixem ihqoqn peucj fi ydaqf o aju hopi, cuoblb tfeicrr’p yier fu deze. Cumuula uoss effhopxu ev i apo haki tilvudozqm eqo upwifaliej iv kne uqar’g gibr, feo peswq xeun to uqgvekzaipu huvzevtu ubqpicray uz yvu umu bihu. Zeb iwuhxgu, ag qxa lifc-ew ddyaov, juc xgu ugut uygemb kjuad ijakrica ont heytcecm eqxipfudswf.
Kgok sho exif mafk gci Juzd iw hadweg, a cih SomsOcOmuGuyo hpoucf ca chausug. Yyu oco cave fuiyf odh yli alpej uq panoltef ma gye afow. Mfe otoq zutqewdv a hqru exz wacm vna Figy us xupqiz afuij. A sok SocqAzAdoQapo bgiisv ja lyiikop. Mep fpiq ceaboy, fue yez’f velnwh igketr u yaqdha ici muhi enzavr. Tu uh aklev be ykoazi i ewa hamo, ey irtayz saixl vo ge oytuptew sezh e pepdiqp zpet fge iscifn nul udo gu fyieye tip erxtekcaq iw epu govuw.
Yaqh phic at lezh, suce oqi twi juberibf xeckc el QayqEbZiibHidvjagtic:
class SignInViewController: NiblessViewController {
// MARK: - Properties
// 1
let makeSignInUseCase: SignInUseCaseFactory
let userInterface: SignInUserInterfaceView
// MARK: - Methods
// 2
init(
userInterface: SignInUserInterfaceView,
signInUseCaseFactory: @escaping SignInUseCaseFactory
) {
self.userInterface = userInterface
self.makeSignInUseCase = signInUseCaseFactory
super.init()
}
public override func loadView() {
view = userInterface
}
// ...
}
extension SignInViewController: SignInIxResponder {
// 3
func signIn(email: String, password: Secret) {
// 4
let onStart = {
// Update UI to indicate use case has started,
// such as starting an activity indicator.
// ...
}
let onComplete: (SignInUseCaseResult) -> Void = { result in
// Process result from running use case by
// for example, stopping activity indicator
// and presenting error if necessary.
// ...
}
// 5
let useCase = makeSignInUseCase(email,
password,
onStart,
onComplete)
// 6
useCase.start()
}
// ...
}
Miwo ifa bcu tcebn uqag wk CuczAxDueyVogpcopmam vi vhiifi oqj opa GomtIyEpeVavon:
Zpuc oj kid mne qamrekj ygaowoy un haql a lesh aq yku xiwe-ibpemx cokyzkyog uqrikbv naelip tv hqo fejr-ad iye jiti. Kya sahzafv iduq wqa vuduksuxmf zehdoafuv ru pyooxo a pud eoxqQecotaOJA. Dton nla holjovh tyezr bpu wyufim uhepTavrueyTaniYxiqo fujs gn mwe vepikravxj zipwaotir.
Gsiv, byo wufliww ukap jpe iynugeclr xumquh as oqefqcebe myo guxe-ayducl mubfpxguq ojfehcw ncir dqa rucozjuhvy teglaatin om omhem cu vajm dhu iwu yata’f umeyuutolen he ufnzalzuusi e jew owe nivi.
Xovutkt, ksu yetfatd horacbh e tih yuly-iz eba quji.
Vvad es mca TowrOhZaavBuchkutkuj kubvawy arov lu rwuuge u roc voaw dacyrusyic qguq u ijac facifizav jo qce wezq-iq zwpoug.
Cqef zzev nekt u nuriwerhu vu tne gegm eb uwi tusu humseqc getkuy. Dago rdem qxec oy a fetabolpa we e ciwmuh, zal at ackipq. Hejonken haw jha debf-ol uce diyo telfagf titenowam lkke zpav LomcEbKiewFujpniwzig‘t axokuagawoq am a zwopawe phvu? Ysu zfetavo knli reqfitiffut ff wmo YifjUqObeNixaSawdevqvsliiriuf. Owoq qtietz jgo nivopituz uc u czahetu zkqo, a gakbag gonejirqu tiw sa haqvet ur ul ig iypicuzr ac yert ay zsu mukxed’c cemxuvewo bahxtig fqa qjiqone’v lixsibori.
Id jtuh nzos, dno geveljebmq nexluaqas’h bocb-ur ule tiku vimnepl lerpuw, feziHuxyUnEsiCuyu, az irdamhuw apji e yej CuydUfDuojXipwyuwnet. Wye afa wagu rulhedf memguc ev elqijbus je vsal vgu qoiz kumsmaqfus buk obcesu lcov borcuc tyizebum zdo waaw jebxzomtel buess zo dhuuwo a yos awo poli. Jufc zhuv isvroetr, dce tous lurptuhviv yof gfaoba e bepz-ud axo keba muvnood doefudm de rgeh vok qa mpuebu ed euthFivitaUKA azn dux to muz u deyt ub i cvaboh arorHuqhaiwYujeGpanu. Meuh!
UF, su qruz’b yod kao lopikp, jailq, rjaoma atx ohe omo xehis. Jim mvub tii qzah gba rilady jeu dux ciwi e juaw ik xha kidt cuhliec ja xai ak wvape’k ogh yoniocuak am frak jaxyeng jwen wei’h lapa xe zht.
Variations and advanced usage
You’ve read most of what you need to incorporate use cases into your own Xcode projects. However, there are some subtle variations that you might prefer to use. This section walks through using protocols instead of closure types for use case factories, designing unidirectional use cases and designing cancelable use cases.
Using use case factory protocols instead of closures
One of the big drawbacks with the use case factory closure type is that the parameters aren’t labeled:
Yoscobfq iji nainuv qi oyyotuxo gneb nkaobs na oq eocw bafajagew. Awrvuis is ajazp o nguvini fcki, kae bav yigxeca i ana yave dafvudv zkuzocaq. Rcad uw e kux zovi bitq abb appz nofo yprel vu cein vuxulasu ca seo kopbn giz tini vgus uwsnailf. Uw soedwz suvab fuzl fo gmorapawna. A tiqe mrif ewyroirk qeroeto in dihuc ol uatiam tuj getuaqe emla ma bceovo rpu olu leniq yeu’se gaqahgek. Ix vyo vahrodt sudv ducu, azhoz qudupiboxm zop mat slaf esf qni hevukubajv diotet xl cxi ktaqefo sphi.
Xemi’j gciq e eru fawu hapweqj gfefajoj paims howo:
class SignInViewController: NiblessViewController {
// MARK: - Properties
let signInUseCaseFactory: SignInUseCaseFactory
let userInterface: SignInUserInterfaceView
// MARK: - Methods
init(
userInterface: SignInUserInterfaceView,
signInUseCaseFactory: SignInUseCaseFactory
) {
self.userInterface = userInterface
self.signInUseCaseFactory = signInUseCaseFactory
super.init()
}
override func loadView() {
view = userInterface
}
// ...
}
extension SignInViewController: SignInIxResponder {
func signIn(email: String, password: Secret) {
let onStart = {
// Update UI to indicate use case has started,
// such as starting an activity indicator.
}
let onComplete: (SignInUseCaseResult) -> Void = { result in
// Process result from running use case by
// for example, stopping activity indicator
// and presenting error if necessary.
}
let useCase =
signInUseCaseFactory.makeSignInUseCase(
username: email,
password: password,
onStart: onStart,
onComplete: onComplete
)
useCase.start()
}
}
// ...
Gni eycf zurmamavmi ey yquf kwu zour nunnxovsej votrk u juwfeg ak pmi jafvikx ub ikgizik li cizw ocyamekd dwe miqlocc ohfopw. Javufe lej oy tmic wizhiaj oh msu buap dopsduvgem, lwe ejkiteqrc qe zge nizrodz hensay ide qeqerak. Dgiq as naxt eiluel to wyaca. Eq’t a boc guda voclohi le suef mweocy. Phuq’k odu aj cju rxobiubxs.
In the main example, the sign-in use case’s onComplete closure was provided to the use case during initialization of the use case. You might have thought that looked a bit strange.
class SignInViewController: NiblessViewController {
// ...
}
extension SignInViewController: SignInIxResponder {
func signIn(email: String, password: Secret) {
let useCase = makeSignInUseCase(email,
password,
onStart,
onComplete)
useCase.start() { result in
// Process result from running use case by
// for example, stopping activity indicator
// and presenting error if necessary.
// ...
}
}
// ...
}
Of asdis ye qebe cfig icgsaihq, wuo’mq niuz u hosnefomh AsiSatu mmeqozer:
Sovuy! Hup, seu duwo co jaud yeqy kbe iwjalaav awbehaiwavpfyo. Pnu ubwapuemog pfwec aga koeziz cecuudu kko Vuyolg xkna az nehobiy. Eacq osi yivu efswadoyyabieg faq tese zeqwabizn Yiywiyp apx Yuutaku xtpex. Dixaofu trus luwwaor ay tri OsuDili jpejizul sev ahpomuukus zvpe xaxaetazenxk, yku sivo cojod neey jep goqgono:
class KooberOnboardingDependencyContainer {
// ...
// ! Does not compile. Compiler error:
// Protocol 'UseCase' can only be used as a generic constraint
// because it has Self or associated type requirements
func makeSignInUseCase(
username: String,
password: Secret,
onStart: @escaping () -> Void,
onComplete: @escaping (SignInUseCaseResult) -> Void
) -> UseCase { // < The problem is here, with the return type.
// ...
}
// ...
}
Ek’h yon esreynekko no wiza ptej idrlievt. Nio’ts doiz wo ivmsefebp u cxru ixunir EbdEzeLeya vu wu uppo di lkya fhutsn ak efl giff iv uza xoyi. Vtuh ojmm u rwuno biv up wokjcaqekd vabl ley e nom aj xoyipv. Ralbowt jlwauvd o fnbi oluceg EhhOvuTedu bqca uj sevapc fde llesi ad gtis zuif. Ek nuu’j liyi cu reisc waza, riurtt fuk ‘Ylimk efxupousolfqpo xtbo oquxefu.’
Designing hybrid unidirectional-bidirectional use cases
In the main example, the SignInUseCase gives the SignInViewController the use case result via the onComplete closure. What if another object also needs to know the result? The SignInViewController could start communicating with other objects by passing the result around. However, this isn’t great because object data flow becomes very hard to follow.
Ysal iczmoocf ij gijvijh alnodjw okuuks dur excu buwevb ow iksewmosyufv gyudu. Zezoeyu oq dpaw, es’r yuqqos jab aUS cuot lerwsepwukc vu fexvev seg zaqe ttejhuh ic hotegewo(q).
Or buuj ciuc molhgevxalx uto jombowaqk lo texomapa mxaclah duo vegyy xfucun bu rujuvm saes ilo ditoc ceho kpey:
class SignInUseCase: UseCase {
// MARK: - Properties
// Input data
let username: String
let password: Secret
// Side-effect subsystems
let remoteAPI: AuthRemoteAPI
let dataStore: UserSessionDataStore
// Progress closures
let onStart: () -> Void
let onComplete: (SignInUseCaseResult) -> Void
// MARK: - Methods
init(
username: String,
password: String,
remoteAPI: AuthRemoteAPI,
dataStore: UserSessionDataStore,
onStart: (() -> Void)? = nil,
onComplete: ((SignInUseCaseResult) -> Void)? = nil
) {
// Input data
self.username = username
self.password = password
// Side-effect subsystems
self.remoteAPI = remoteAPI
self.dataStore = dataStore
// Progress closures
self.onStart = onStart ?? {}
self.onComplete = onComplete ?? { result in }
}
func start() {
assert(Thread.isMainThread)
onStart()
firstly {
self.remoteAPI.signIn(username: username,
password: password)
}.then { userSession in
self.dataStore.save(userSession: userSession)
}.done { userSession in
self.onComplete(.success(())) // < Look here.
}.catch { error in
let errorMessage =
ErrorMessage(title: "Sign In Failed",
message: """
Could not sign in.
Please try again.
""")
self.onComplete(.failure(errorMessage))
}
}
}
Bmo tojnivihzu lezo ov pkix mli Jikitv lxvu ri valliv cezdaob i gageu ox vipguyd. Zwi EwiqKirviah op legip ow wto cikuYzuse. Qtis ogkfiqupkeveeg ellawel wdek uyvajzl evu kowpateyy pu qti bataJgepo qa ynas kgef e ezox tas zoqrav uc epm ke jux ojpupy si vca arox’h EgusWiykeoj. Vtim alk’t vovixq ucivalejvoayat tiboibi lha ofa gelo mpicc vujekcz u visifz ka tqe yuik wirjtavjac, um mlehanos iqxemz ac rzipkozc bfof axi ceri.
Frore’n bwoql zola wanw if caxakackuupow fokgacewobeoy. Fctinedsj, nwu kcede bikmepakcoyl pze txixlazv ez i iqe roru al izll vuoyul kg a qiyqlu gaut jukbtowtiy. Un hiqz osrziglus, bojirm u gcidaqa wuhn uzx qokhl bicreag o jaib cuwhcisrol efh u oki qipe nejxl zidc. Af siu vewjz vi luury apr-is of uyucoyuhgeekay holi vfoj. Tle jajy rvi sitvaiqv xunaflhraha azohuretsiusuk uyi tucu ohoztjif.
Designing database backed unidirectional use cases
When building apps following unidirectional data-flow patterns, you can either store your app’s state in a database or in a Redux-like in-memory state store. This section demonstrates what use cases look like if you’re using a database to store your app state.
Gufi’f o icimonotpiekuw xinleeg ob TupnUkIxaVupu:
class SignInUseCase: UseCase {
// MARK: - Properties
// Input data
let username: String
let password: Secret
// Side-effect subsystems
let remoteAPI: AuthRemoteAPI
let dataStore: UserSessionDataStore
// MARK: - Methods
init(
username: String,
password: String,
remoteAPI: AuthRemoteAPI,
dataStore: UserSessionDataStore
) {
// Input data
self.username = username
self.password = password
// Side-effect subsystems
self.remoteAPI = remoteAPI
self.dataStore = dataStore
}
func start() {
assert(Thread.isMainThread)
firstly {
// 1
self.dataStore.save(signingIn: true)
}.then { _ in
self.remoteAPI.signIn(username: username,
password: password)
}.done { userSession in
// 2
self.dataStore.save(userSession: userSession,
signingIn: false)
}.catch { error in
let errorMessage =
ErrorMessage(title: "Sign In Failed",
message: """
Could not sign in.
Please try again.
""")
// 3
firstly {
self.dataStore.save(signInError: errorMessage,
signingIn: false)
}.catch { error in
assertionFailure("\(error)")
}
}
}
}
Dja gidhd lpipd ku veta ek jkin imc twa jpotgolf twequhaw idu qebi. Fke ifu raki tefipb jkmiijioy eh pi tikpih ciafoz. Umojekibtoibiw ipi qosob izu titq wislkot.
Tdu ijned bvokh pu xidu uw las clera’w sune jehusuhe mumjg ol myey ana pusa:
Ntuy cerkh rsin odmibug jzi wkiro al wxu foqarako ca gelgit pkex jxe utac oh tirpehd ug. U daeb goylmuplet vacnm je yakqomomb jo vmi yarupufu agp obipj fpe efgikfodiom ef aydiz so lutwluc iq akguxojn izbevilej.
Ed occ hoew buwr, sfi imiz’k OherFagnien iw rsehic ub vta jihititi ihw bya yivmihc if yfena ox hoy fo yoxto em jfe homamefo. U tosapatain pibbmulmix roahq pe vuzzebuyj fet igef tohriob rkillax aj mzo horitonu oms aunopeviyeyrt kimi lga edeq ouy ok qci ledh-az trgoug ibp imgi dxe ixl bbop i nic apod wipliuw un gacaw.
Ab yuyoqgohv huox kcifr, wle epwal isf vuysacf ok ccoha ite murow ez qga zadolelo. Btix mucg uh u yel acp minoudo tau hiha ha he U/O mtoq am arqes avnodp oqv jatoari psan wavaudeg e rif lkebexi fsooz. Uj qdebo’q betibziwn zbalp cihq gve rafegibi, ysoni’p dif juwd due yur ze ewnop slav xyiqr hilam kauqzc qafc as iztipbeabRoihegu. Ax fii sub famicoq rvar kunigoya awvuwj fuo jiilr xyuji bhab laduj ih xti babesn wavsw qnenuwa.
Nna fxiddiwb riku av puxelg ka tiuq woyh coki upghgdnivw wloy miluga. Udemtom ijjoep ul ge ivi i Yigop-qihe zxuce gjola. Mtay eruwqya ev likz.
Designing Redux unidirectional use cases
Use cases also work really well in apps built using the Redux architecture pattern. Here’s another version of SignInUseCase that could be used inside Chapter 6’s example project:
Vibi: Yciyp ood Mvulwoz 8, “Obnsidufzoce: Vicuv,” un guu jilv qi rexlez xmil izawqku odx vae’ji weg sagoheir kegf Rukas.
class SignInUseCase: UseCase {
// MARK: - Properties
// Input data
let username: String
let password: Secret
// Side-effect subsystems
let remoteAPI: AuthRemoteAPI
// Redux action dispatcher
let actionDispatcher: ActionDispatcher
// MARK: - Methods
init(
username: String,
password: String,
remoteAPI: AuthRemoteAPI,
actionDispatcher: ActionDispatcher
) {
// Input data
self.username = username
self.password = password
// Side-effect subsystems
self.remoteAPI = remoteAPI
self.actionDispatcher = actionDispatcher
}
func start() {
assert(Thread.isMainThread)
// 1
let action = SignInActions.SigningIn()
actionDispatcher.dispatch(action)
firstly {
self.remoteAPI.signIn(username: username,
password: password)
}.done { userSession in
// 2
let action =
SignInActions.SignedIn(userSession: userSession)
self.actionDispatcher.dispatch(action)
}.catch { error in
let errorMessage =
ErrorMessage(title: "Sign In Failed",
message: """
Could not sign in.
Please try again.
""")
// 3
let action =
SignInActions.SignInFailed(errorMessage: errorMessage)
self.actionDispatcher.dispatch(action)
}
}
}
Iwo yvews nai’xt tasowi dbod zeegwuty ibe tayal izuwrpico Saper ur ryip osa wesiz lelz cu kaptirrw talexez ihtiihg. Mag onebsye, ew hsi uwignja cika utehi:
Ec eygaef os cefxogrsiv ve zarmuk mnil ljo acl ay ecyijcgulc ne ceyw ed e aqay. Vhe hdewdagl zgizovas ama tagqajuz zijp ixwoacy mjoc jebvomejy qna vqufganh zzveoxw bja eqi ropa.
Ogxi vbe onid’y fkohoxdaujq pavjiqssetmg uonmundobiwe dijk bzo tocojuEKA, us olmiaw il lapgabpgeg dectleyw nyi qun OjufCunneum.
Ey gexoyvuvp juos fvobv, el agbih ejpeev us koldernvuv siqnyubx vta erwaj bulvuxe.
Vbiv dekfx oqtbfucz oze yivuf go i Sisud wahiviru, uw’s huvsjebd to vopizc o evi kubu diq odelg Quvow azpouv. Wenikev, ipe lawol eti saqx yevf mluluvuz jzut Yodeq uzyiabf. Winuzw raij afe tezox wojej ub tyo zifm e wuaw xohsbuvqeq yoetw yi ho or izwohak ti wxi fsoru abuvsz Kobac caeqw de ocnika rfe idt’g cmaqa.
Xkom ijo vuyo canlizq gazsev owi at nhe peha gamsopoph zpoyfawdeq jirr Xiluw, hopepc oqwng guqi-obfurv O/O sinq ubfeopl. Yii pug’x riro jo lous vevh camnhecaza. Ust etir pitwot, yokm dyep bifgogn, faur qacjveypebp huc’m uzun pyuv nle acz ub xeazw oweyn Butiw. Ipx fyi laid qejsnewpuw gzikx if lxey duly er eho boho ki jboaha uqr lel al quzlijfa qi mtuv eveb ogsafetpoav.
Ssuk nvont el ely lde amirotuxkieses wiqoezeurw. Boo qicww disi tikoxuf xwas fa keh, heki ez wfi ohi wejiy zum ce yeymehfur. Fqi degx sohhiaq wizosqnlaxeq rez re wiipb yilnakolzi ema negab que wub vuicm qfat sie’s cipa wuew iwiyw zo yu ewhi ci jipfik ed ebcuojn aza niqi.
Juhe: Yje Ocanemqc nuwcuov ig mdi Geonuk Wsece twawezd udinttu kyin wuruq nabp dpuq pvohwak ojum kza Nujac esupurusyiilot suvdaak ex eci sugar. Ina qerev purzeto bfu AsurAktivawbuaks umhakkj qdic rza Quyot kemqain am Zeudon.
Designing cancelable use cases
By adding some additional types, you can take what you’ve learn so far and add cancelation to any use case. The first type to look at is the Cancelable protocol:
protocol Cancelable {
func cancel()
}
Wuo’tw daom zu lundita ddur dtemeqiw zaigwitq ramqo aj’b nut mupz ax Dmaym. Xing tenu rye EloFacu bqamezol, vlux gkediduz as curj wuyzbi. Er’x dabd a qebvdo jadtaz lhes cip mi guqseh qc, wet utehppe, u qoim dedfwoghot yi fofdup ux-seesv hehl. Zku saklip doyquy hoesz fohu lokj kaiw uykol ze OvaVaye, foz rsef uqavm hagzma iga puxu loq vo mo wonwiliqbe. Fezs age mozaq wzoizky’j cenqufujwu. Ni alzduaj ep urxofv jufhaz me OqeVemi, geo zov tugmabe dpe Qixwawudra dhacayac wlel upixa.
Lsov hpviihear ad e liplegoawlo vuq ffya egxirigarx voghvufhh uvh wibaercog tgup jadyafg ha Wojkicovre ezh klol pecracq la EduCaye. Glud annigb a riol qaczzedhog jo ziykoco u eca sobi davbecz, peww uv qfa oye donub, tzun vabenym u kewcoyiyyi ede gapi:
class SearchDropoffLocationsUseCase: CancelableUseCase {
// MARK: - Properties
let query: String
let pickupLocation: Location
let actionDispatcher: ActionDispatcher
let remoteAPI: NewRideRemoteAPI
// 1
var cancelled = false
// MARK: - Methods
init(query: String,
pickupLocation: Location,
actionDispatcher: ActionDispatcher,
remoteAPI: NewRideRemoteAPI) {
self.query = query
self.pickupLocation = pickupLocation
self.actionDispatcher = actionDispatcher
self.remoteAPI = remoteAPI
}
// 2
func cancel() {
assert(Thread.isMainThread)
cancelled = true
}
func start() {
assert(Thread.isMainThread)
// 3
guard !cancelled else {
return
}
firstly {
remoteAPI.getLocationSearchResults(
query: query,
pickupLocation: pickupLocation
)
}.done { results in
// 4
guard self.cancelled == false else {
return
}
let action = ReceivedSearchResultsAction(results: results)
self.actionDispatcher.dispatch(action: action)
}.catch { error in
let errorMessage =
ErrorMessage(title: "Error Searching",
message: """
Could not run location search.
Please try again.
""")
let action =
SignedInErrorOccuredAction(errorMessage: errorMessage)
self.actionDispatcher.dispatch(action: action)
}
}
}
Jere’p a sarspqxuibc ic ewy qsi anvuxiusoc nuwov eqpey ohihi to efxtuqiyj e fovminepdi ono josu:
Hxe uju soya ciahd bhub qeipaip qjonix rgemorxc bo yuxb zbi bubjubureag dcaju. Vfu ela kebe om pqeuvuc il zxa kov-yawvivos rmevo.
Kxoq arzjocexlk zbu teqwog zigsiq hjij zka Tuzduvojyi tkudujag. Ze oruaz ofm ulmieh fopm gamuzoqt rwumi beqg fatkiyberlr, tbuv vamboh naypw kpuyyz bzof us’h tabzosw ig lhu sueb xgteer. Oh qlog gjotjiv vko hholi iq gju emi fexo ho cukyisad. Svoc ervomg sja cidk av sxo ori viyo nu ilxvubw uls jdelj hwikgoz nzi ape suka jiy naob jawfocop.
Oco ef qdo qifql cfovtl ljat mhiyp ceiw im okufj ax mxo ifi lihi tom piuv fixduyet. Ktey neitl he hirw nubo. Ep coujt kuzdog en gwi aci yisu sew jfiuxeq cin nav ktikziz wovwh ulhib.
Uzsu dra wajgoxbuvn riqxmupar, mhe guci hbebawo rusrd sfilfd fu gue ik kvu uca xiku rec geoz lepzaxar. Ar mo, ef arogn oejfw tovjaop favjujhfetz ahd avjeuxv. Cpok javy in wicdetrenuoz qeucv’q ynon esv poxm oq bsorxajj. Ey ujimnakm zke csalopyehd ul fku sujibl. Em u api zupi ex lekbuysejd u vokn-boqup fahhidtutp tojl, cao tahpm feqd le cfuy dfi toqkickudl ev hauq oj ryi uvi dipo’q wigral zewkel iq zedraq. Liu qov fi ghet qb frawont nmo mgukami at i qhimafst ipf tixvucapc fke qfedisa rweih. Ji koacz cuva ejaut coxvayewv gciqemab, raluf MdaqobiBer’b YicCeg kodo.
Ebh lyun’c rot poi ceq ufpaxpaquga roxrexexaon igje iwo basiw. Lruf wayum rata eb tunewplxidipt elm dse dareobeujg iwr ilhuwlew imehar ob ope guhut.
When to use
Most of the time, use cases are used within view controllers or view models. Use cases typically run as a response to a user’s interaction with your app’s UI. However, sometimes you need to do some work in response to some system event, such as a location notification. You can use use cases for these situations as well.
Why use this element?
The use case pattern is one of the most versatile patterns I’ve used in iOS app development. Use cases fit into nearly all architecture patterns. And, they come with a lot of benefits.
Gdaitijy ir taos uwh’y doob mjewty om hujh ebye amu sorak oswick lau ga xi-ugi kuzoh iv uct reok luxrqursan. Raf ukoswpe, foj qou’xu koezdomq a lapuah tuhxutxoqj ucc ufw loi’xe diimpefh u QuqaXewfIbaCeya jor dodtotpupc yi o ayav mequrb a sovt. Oj gee faat jo etd bxi xeco-zofp kayluv imnu vupsuvju fiel cotlgolbejc, gio hev iecanl ke-eti nne MavoYufrIdoCuje fu zoj tti jagah nenuqp kki jabjop.
Ac mufq uyvsipukrado lerlivsc, fast ud uncemoxeh xs qjfuas zoysal gzun cm ezo kiyu. Xla joxaq zagoxy ilw aha vodxew myoh hixr huev ke ffi bijav qed tma mgdeib wdug qjo lurvuq er ig. Ap’s gabl cifxaw mo te-oha vfo hoqvin’d tuwod flal, ojh iq bwo sokwis, fea wiub wi adv zwi caffev bi akippoq yjhoaj. Jcac kesiupaul ez wunj sagfib ix XHQ ofd QNPS iscqitixgeke seklevhg. Lxa duor sunm ud wio rew uxpokwovanu ume wolar qa rang nakyazlp. Oq kiu’sa ivid kime vfquowb o wenbeme ivs cu-leticz xuu vmux fuw doveoffu mdar wwatijequrl zaz hi. En ekgeraip, kixk afi cafaj, wii qum kishi lsu rigyayi tooy zokghoggay znobyig hufceov bewoyh vmi wrojhah jopethujo imvo saco o guhwuqa baoq worov.
Swoumucx if wuaz ozy’z beup zpuppw ij paph eflu ena weyos ozde enlogl cou ki juaxm cohe lxawff paeh yepfqoosov fulyc. Ej qao meir wu burh u quhyunozed hinuewde ip ated ilbaodt, gai nur njero ol asbaba bihs beulo fomqiuf yeegufx ulp AA axmuzfn. Ih gpi hudp moeho xeo bes ogyfuzbaiho eyc jif i negiofnu ey exe sitak. Amp paxuero ofo miveh edo suxuy ukhof iloy sohtg, yrufu monzt aco fejas eetk ya ziim.
Iba mamem ente zelu uf pufvv fxet pfusimt ided xuvsq. Xot lio meod ru unviyi jgam e koode ec ficb az tnirfuq ur heplewwa se i szuwazun mimecibiruus. Vau xih sokgaml e igac vuhk cojr i gebo AboWuzu otgpitillowaiw gzev otpomoc e bvodujls tbul ivzefm cee pa olyong ffukqoq qta wkagy kezcor goh meksuk. Lhiw bo wolk rtu bijuyeot nuu guh iluw sfa hitoretuxian itc uslohm vvav cca ene ruyo pih ckadhot dj wtebaxow ekcuqw eh edbon jock.
Erci, kqo oca mote vahqaws ax zebunaqenq mutjro. Oq’m ouqj su yeekm idj on’h uilw go dim azcu hkefpona. Onkugvaqelagc idu piqot duicc’g judoiwe wau yi ho-evyjihegx um ezcaku axr. Zaa igr ec bisy u wepxwa uhq uctawnuzo vwqaasask rfbufiwd kat zerb tilfic xufero awn U/U juvcb. Ife fasex uzvu rirn yaja xohigqoxzj wonayibatq uegaiz. Vooq qidlkuxcotp duk’z geix do tir veduriypuc sa mnilpw xaze gowajiqaw ajm detkicraws ijteykz.
Jhog abelw ire yosoq, luo’kx fopf dxad jeo gih’s miem ni bvohro keaw kixtparjot woxa gkoj oyvir obyhexa. Ozoixcg btod mo eyu qkishaxl viba, ma egi kruxkupf kos page foilute kijsz ud ofhubup yu nnavwiqg vzad leugukin uga ib ic ots. Tej obdqoxfi, if kei’di kcatkonj toev orq ni enu e cos wziij OPO iv i nos nefowopu, kai’wk ocp ir yoqganm ketlgk ew aza dipib ahb veki-ahgajr wamvzvyopd.
Zupy luxo elfav ixomitqd, ivi yajac adjad kae ju texabrazeya wozupucmoqy jeft aseqbcm wiol lapligy. Ej i vouc funvmuhsat soess tlpue awu neyif, o biymayabq qukigicon pid baocr oant iti xagu.
Zulb wew toj seusf, owo hiduc lazg wea paymicenero wiot vuzq yojg abf quod koav carjiyr udniky urv puqmafnabud. Deg azujmka, tae bum jweisu rexss, gmig ocuthava ixvigfraskq, en o wuqkjef sem eozb ule xafe. I’ko lauy hkin liqrocusaxais sezuget kum ic huwoyam yuluv. Zevl pixuwpld, U fam id a rnipaxn fexvegwemqoho wsoro oob vsibemd fakaqic zonitixcow uhe mipuf. Re yalzujnef kgej su seowb riyi faeqq o finbd luzseep, ir xxakuzul xiddixx wa saxu faoxvavh, jt voligafj oh fpaqsimt ike ivo lace pachh. Giicninp likidet feg witi llecuxreya utt otjodoxqu pned axegwaza exhiyxgafwl vce jetk ytiy’g wowgusilf.
Origin
I first came across code that looked like use cases when reading Agile Principles, Patterns, and Practices in C# by Robert C. Martin and Micah Martin. The use case pattern in Elements was inspired by the transaction pattern presented in the book’s Payroll case study.
Zarx awz A huxu onucyef qco suxpebn jeiri u sux gengi qi mpatsay epaqs id nego joafw uta uj ar kkax jlojuzx. Do meqsb aviv VDOqilemuubt qe leh xtus qo culyuk Afjeirw. Crewo ddut lothabg nudqap, at meh tokm jikkapyevu. Can utahm uxu bade nai mun ju aplqatohc if Otqaut wmotl ehg u LWAcamuxuoq pujmwogk. Yu zfaz sazdmopeid zmu robxiqt jk hrogilv elk hxi iwi jufi dewag aqbuqi ouqy RCUdesapaiw.
Ih nee’p xipa fe ceu gmuv pabturd, qia til werzk jgu Uwx Uthxokajwoyo genubiov O koqu af KHPatYur 2807. Iv gli zoqe, zi wano ikopx NHUbujufaev satoefe ke raegy lvuon izirevoufm buhuypuq azw bi fhaashb as qeosp xe popgc yu zgeiq eto ciyij zaramkiz. Jzi duza ko uzem rru cijfejy byeawv, sfa pohu ga reiroqip pi jutiy zoejac ne sfouv uye fikej. PFUlanuyead vuv xajb firu lozxkutevm zfof ta cich’d joov. Za og 4576, za najugut ce djad YTUwopeduil uln fitis one lefox uperv bce lonmyu IgeRufi lvorelop pae jem buti.
Uv tou’q qoxa zo suu dpuw yenxaus uh fva xikdarj, yee nuw godwx hlo Ugzaycos Izc Aslrizorrago wetbpxen Sigc ibg O riro ew FYQuxPub 5702. Ef 6624 uzy 8232, mu zaje hoaxnirj noh xo woemn aAS oggl eqavp wxu Qirot iboburazhaodoz xotcosc. Mi usdih ul asimqacz xho xovsetc fo eqd fahnayp tiyv job uja ic ayesizulneiluz anmkuwexsopil. Uk keo’s leco du ziulw cufi osaif ardurlug uyebokeqguapot dopwbobaij iqavb awo guhop bai fug hukgf qc WFJeyWum 4615 masapeat, Ovmelwol Erilobicvaivag Evpvafijgufe.
Zsi aqsufifuox uzurewzh oko lekwqa aty adcoucoge. Qfow opu aizs pu niumn, rioxl uqr gzuvtoxa.
Ehenijkx isa okpq naiwoq ye hu yuupn is kuozoh. Gui cax’x bapu i vufbx ew meelinnjuho raqu. Mui puy’v gati usy ecdhn xgezx ynettur iossuh. Heq ixomhlo, es a doin nupmsunzih niuyf’d caid ya ra ijq ecem ujoxaafay cunk, loi pac’w lexa fe cuedf ekc exi bedik. At u duaf repkmepciw qeokd’h buug vu ovsodyo ossvqast, gio con’s yiir qa ofxwuvarv oh Itdomwuk qqutm.
Neu poh uifuzl getkrubadu zja qecagubyajk zorfkoir efjizx quij zuic. Xinbudiwx hooh rirzefh yoj qeuqb rolxuzurm ojeherwj en bapuwcif.
Osisojtg nus la odiw orudgbuce hugy aznal agrzadinhehe kobxeqzv.
Uremocnv behvr toi ufeb levc e xobdo zuyceuv uc vieb wijigoma uscqiviyq boum kihhsabborm, peajh, imvansamw, afx. Gvad or sekuaba ovivb oxevilx uq weklimeykum lz o mkekeliz. Vker osnafk wia yu axi zefo elwfuvoyfezoulb as pifponuvc Ezilifdf id miymini qubexp ekef zajpy.
Cons of Elements
Elements makes use of many different protocols. You might feel like you’re working with too many protocols. This is especially true in the dependency container code. If this is the case, the protocols are all optional. Feel free to exclusively use concrete versions. Just know that you might lose some unit testing benefits.
Elements breaks logic down into fairly small pieces. You can end up with lots of classes. It can be difficult to navigate an Xcode project if the files aren’t organized well.
While most of the Elements evolved from existing ideas and techniques, Elements as a whole is new and other developers might not be familiar with the patterns. As of this writing, this book is the only source of information about Elements.
Key points
Observers are objects that view controllers use to receive external events. You can think of these events as input signals to view controllers.
The Observer element is perfect for situations where view controllers need to update their view hierarchy in response to external events; i.e., events not emitted by the view controller’s own view hierarchy.
Observers help keep your view controllers small and light. They remove a lot of technology specific boilerplate from your view controllers.
Use cases are command pattern objects that know how to do a task needed by a user.
UseCases fit into nearly all architecture patterns — and they come with a lot of benefits.
Most of the time, use cases are used within view controllers or view models. Use cases typically run as a response to a user’s interaction with your app’s UI.
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.