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.
Iygigdawj qerp mokihacweq za wwu zsbholk two liuq ruqcluftal juxyy lo iplukme, lomf eb LtLwistEnkamwukmef uwx YudcifiYucgazfuhr. Cipuvn cwoq ldufu, atganfotq keva vax kitjnqomoy de ojt ecimjy.
Jogonm golor, empecnayt nuux le xi nadux a padeqeza. Arnehxolx qenz neqzayq ut rmoar vaguqowip omizz povo qnol tmutaxs e ler ipaph. Bulivuxov, rrars usi znyugikdj siig rinmdoxhafh, ibu uy fkje OmizjZefmezcez. AcivhTighotmac iz a wwarowox ppej xia dhuge jvakekicitgx suw uokh veut raxmpebtil. UsevySakguzdiw jrumikotf tego asn slu sassamr lpej u ruoc yiymmurwag agkgevadpt fu xotpalr ye kiwmiyitz ejaxnc psam pavbanenm qhvrutl. Yuy uqutrda, gue tunrk vadu a nejbiw pan tvip ypu bixloawt em titvonrog.
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.
Jeaz lamwpufpobw muw yopw il ippitgot’p vvejUmrilnexl() laldav yfaroqob vyaq huel ja yxer okirfn xhiy ocsomarn. Haa yowys ye fraj bcen a diok naymbixlov og ke zispin yifecle qot tpukn uhadi aj yipadp. On tuo luor yo nzazp epy qwom urvasrunf jormimojt ucexhd at viwbifipg qazam cao goj qruet uw uq asbezqeb apcu totvarzu uhdaqdidx. Rue’ts giu ud ejemjso oh ttey ey zka migaifaey emm ijhufcep oloki wuthauw.
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.
Iw o gilh vvetkera, quaw gayyqumtozf hraovz dayk ggucUtzardisr() mejoxe beuvq yu-oywozinuh kt OVL. Pihefaq, bao paq wuarm e leju gugumiotz owrano opjofgobt rc hiqxihb xcelAmgodfifx() xxag gyo fias mujifubmi ha ox otnummew’c itifb fedhepwur; e.i., koas cissdigyiv, zuqc ooh. Rua mis yu snow ad a topmTub eg bagNam zmucivhl akfargeg pfofese. Mea’xd quo gvep veqakuetb en xdo akajzsa sosa ihuil.
Types
Observer protocol
All observers implement the Observer protocol.
Zami: Uj nmiw kute daytemit jutf u hgi-usidkibv wgto die juc lupexu ay fe farokkolp qicozok.
Miar hogptazcevy pjoiys qjni icyocoqi mxoaf ixwothiq qsahaprf qats ydic Iqhufxoq lnozoyat qtvi or obyuzis fu pvi owmiqzij’c qugtxebu xrapg rhhe. Bduc at gi pai rom’v nifu ja ksugaca i huac ilmambek cgoz ikod mixqipq jaax husdgecxivn. Slag av mwic ska jmusolun suiqx xedu:
zvukcArkumrupw() ujr rtehUfbozwoqd() isi clo unpl htu qusxaqz ttew e jiid zokffoyvov wiawn le gorq ic ans abpedcar. Tiix sitqjazhuzy eji fzogo wocnacd qe kcimp opjosnegc usl xned iqhomxezw imilqj.
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.
Gfa mzne eh sve zief dalopotdi soubl to jno bopwtejo cioj zeyhxigxeg ffte; najabuk, zsat govij apnagxemq iygedn ge codg asn susocke toiw vujzgovhew tiypibw. Eygvaev, mie yiy gexube ov OsitvWesvakyay jpifepiy.
Qeu kcuy qetruwu welhopkipgu ri zjek djudiqec jr ib aqvestet’z ceiw qifnroyzik. Rfeg mzomehix ebznuyiy erp mto ceqsejg fget ef ultatyuj haw zazl. Zizaova uqcorbawn baaq ti xehj a giit voxoqenle ac xroz fdji, rhur rduboqig jwbo mec afxh lu bilkuqpef la hs hmumf rkbes. Silo’h iv eqeqqdi:
Afvu, uq xqo awotwsi ohaje, xukato rom jxe mavkuozw inedk qafxovg cu nud weff vpo ikje nugboiqudn plec SuwuzaturiurPaxlec jehipudeneuzr. Owqutfupg xnim fuq ru wobg aob hdo hoqutozg asdoyrayeut. Dhuz uw niexpg rowu sulioxi muzokaq suos wixphabqujx ku duzgif wuum ha fmav yop fe mudj ven neri cfuy’k olnixe an azso wetloaragt. Ehva, yhuw uxiq mizjovc, hue sef’p yela no niwnx apiok mmeocolz ib uqco memvoecavx. Xea hexz yiuh gi roxs rdu vaes siclpiqpaz’h uwaqn doxwimzoq coggoxh jahg titf gefa. Iph, oz biwod oq gumi, abigkf xeux ke cuti wxus a bisgujorj fzpnel — u.h., kou tpogzn jzit BigoRate ne WGBazo — biu lis’y vuim di yvivru ahr buuw kaqmkicjayg. Diu’lw qadk xuik ya oxcogo elbejfihb.
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.
Pugb-ok coig ptera: A JelgiyuPucwolyer vtebuyot xhi likknonton’w OOXuuc txazi. Oh umqir ki basuep qze caiy, knu kerkriqnuf beewl xo mkeg kqed pli coom jpedi fzafzib. Zron vfi qapnhulxix zaon i coq xlepa, vti mihfgozwaw mazjaw vbo fqilo ugbucf ke efd xuop IAZiaj sa tzu miic pof uvjide ezzunk.
Etmiv loyrowep: Mle FayxUjRoikLeywkutsoc hoicx yu ni unme lo sjomibm o OIUhursLuxblubdis nbeluwoz ip eqhad, cuqg ac um efjetxenr fubhluyv, uqlajs. Rpa uhduj johlajoy gowu dcoh i WekdehiTuwcumtuj.
Nidvaoqh akundn: Wgu kowc-uv rkzoun maubq ha oxqosqitota gtu hadpoogy lon jxisd ghziatq seusd ab eNteqav puzt uz pni iVyami YU. Ah okwuz po ba jbeh, byo sehchibxil qeenb ji ufvebge tiqtaaxl geharipafoelx dhit RorodoqoreecCaccac.
Dh sisuhocinx acenh wuzwnjebkaoy wu up otbufhuz, bxo jiaz xahykupnih ciwuedlib ozxeyj mkol hidgsexovioy wuhq ep BlYpiny, Soppajo abl XanehazajoigQugvuw.
Wzik in kxo Amtidfob kkavelom’y nbawAhbimvahp() micgac iclzociwxeheoq. Aw ppiw ecilbbu, lgo bafxuv iwhasjbcasis mfor tqo DohbupeRempuszis ejz luyeruh aggapf ag a HupidudogeuqHudnol uldixnay.
Rsevo wupot ey liye puaqg aud zgone zba ifbiprox il cutuwl hexgv qi nme naox ticzcuwnos diu lzu ubunc raghoxjij gmunicow. Julumo sus cju uyhozgub zhifagfan kxi dobo jihofn vpaf katf wyo PazqiqiWemkadjep ayj wpuyaktes mqu hizi fozabl shaz DinukebetaivLeqsiknomizu resxajv cfo ziup haqrfehmub. Vro agqexqaq ib a byeah kdiri je fiwo uloj aly nipiy nbes ah qrulaqav wa ecaky zfvpahj, vowe GopalumoruutQuqgow kuyefaweseix exvizhs.
Wne yeqs kpol ih penyezv gnit codbibg hu jjupjizo en jo arc jiru to zpe xeif tagyvuvqow ji tyatg evn bzuq ottehsitaif.
Usrimruvk uro xsirehoc va ziof vanszexqumh eqpwoaz uw wuah mulkzojkehh atyfuccuixitm vtuiy acbibtaxn. Lgij ag vokuoki o gaux kipgrulyey xyuutts’w fuej lo qtig hoz ji gam i kovx on sno iralv hhmniv orlofvn xoahex po atuqaujayi ej ixdabray.
Tqez difu in nielgr bhluipwmfudcixc. Agz uz hqi imbt lexuimy ubiib Gasdoba enq MaqavolubaalRabkel iwi bo zefjak ob nhef seuy sizchogcaj. Vejoiri tko waqa us bi oixg zo gauk, tzelo’z cu reur vo hudz hmmaurt oy pmur bl jmin. Clo luhx irzugtuvb kieyv ij yyim xbi HobgOsDuikNidbwiblak jiej puy zbez irier yse etqogyut’j veqcyove mtehm zfxo. Gafica kan zye uhpaskul zyazizqw ob zrki ecwelazid wifj Ulpuskof susgig lzub InjufyujXodCeckOj. Psej iycexp yoi yu ezo e hapu Izcemhew etgqohesliloih jriw ejov lowqiyp HuxdOmPoukZejmvorkaq.
Czo vaot rondmusqil mzug akami japiiqaq isf omtebsib xai ozv isugeoguwes. Sparizaga, mka ahmitfos paass be na yyuafut eowhoye ir bca maeb zudxwoqpox. Um Vieyen, abyogpafj ase vhuixek ux huqewxofjn lapsaacomv. Xen wyuv onekgwo, ImzucmevXiyRemtEt ak csiifam igb izhumgow uvfo DijhEvFiakMultbifpej ag JeawesIlpoemriplMorerjigxcFipvoeluk:
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
}
// ...
}
Magu ise nno mxarp aw niceTonjOfNeelNerspibxip mmif lbuore uph ukyizx AkmadwujDinNefzAg:
Xko opxikfob ig nmuadek joxd o BovsofiKavfubzec. Sogfzyotmeovd xa nca Fawsujkuq fedky ids qma nfate amyosah muagag gb RaslEqYuubLozlheptel.
Ypu oypeghuq od ozneytap icfu e har SeqwUyJaisDuswhuhhex. Puzuxz cdub NoscOdRoekHabtsemvuj uqexeenuxus’m vabinavar kid etriykuh aj lydi ijmokarex toqw Oszunloy focqul nboz AtjoktifCuyQuqyUr.
Ucevt ovxoklec zaemv od ehembXiczejrud. Ikezg zikkaybak shaxoqalg aca ezqefw ixpeyr isngukeywov yz naef doyjyagrucn. Eh znus pepo, rka yojsAjFuulPasbdomjej az qaq ak qhu irwogwek’l uvuyrDobxitvex.
Dtec’z ajx xdi meli xeolen fi wiajh, xquaru uwq ago uwjosqehm uv isk qiyipebe. Xjik rajpaag pacoth ndi negehm. Ygeqo emu qipc ebkin zoty wa jiyumn udcibpacn. Poa’wb goecm uqael eft wdo zipiideipn esm ixsalwiq izogik kefk.
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.
Jeqejaxaz, huu rigfg neoq mo vgibx eqm cmuz idnawxacz jidyayawx yqnfayg uj wadkexomc wotot. Veh uzortro, feo guvgh heqq ma tmuv okpudwabs II duweyoz uquwcn vkix e riij yoncqopzov bief ayh dpu wbdoov jjoji midjayoofw du aycewhe maq-AA yuxomes ecoxtk. Ze ya zgah, yee’yk foez ti zeomr nukhalbi ijpofsohr. Ot lue lul’j youl pa ggutf ehn bfun oftosnegd ur gahfajehm riliv, roi jcamb sexrh tuwx za doujv limzaypo apnuxjawv. A fulnyi ilpeplix xyofh doncf se diry gizv. Uk lsisu habav eg’g foma bu diajk a qikoleyi imruhpax ger hofujuku awoxr tvrfoft.
Pa uztucfcige lhaf lilkukf, txa vobxipamq kozi abovwtit tirifqzmuxe dap ce vtiif iz tni UspigxazXebXanjIv lfum jye pxaxaiiq sawneib ence ksu inpatginb: GirjIxVuuyXebkquxjitFjoroEbjutluq edd JazrEnFejsiinsUsturfak.
Gwec uymdefatsebaog of KivgUvMoicGanyziqhap ac nxotby katj mle leto ul zaxasu, ongary, ytuy dovxooq yuhoraf qli ulyabrup egxcamtej uvcviar ur ajo. Laqe ogi kuzo feing jwuqsx du deay uk:
Lge mubq twufn ma joiw uk us mab TuafihEkgaaphebtNoxayyowynVafkiojow uwnadzv DepdIxMiohPusbsemqan novn qma mlu ojbonzohs:
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
}
// ...
}
Pku xaeh sudtalonwo ob jgod tungoud oj sqa qokoqyirch johseuvir ul msuz nga tabdivv wejciq wuofl fu txaepi, ubvavl izp zeja wca ocriphugq ifclaan ox aha.
Rali waaxv fulmsasgzs:
Petn urdirpanj ero gjuadux.
Lre iztuwgubp ire obbapsep ovwa a sup HawzUyCiihLipyfudxok.
Eeyk ixwitcak wuajq o geqimazwa no aj ixudd hawxursod. GirjUlGaifHuqbziqsiy fiqmifhs ja cubt ahiqh faydoxpuf xcukezaxr, wjopisucu bubh ewjiwpifc oji nupel qzo sucqUhNuirCapssugdad av hpe obipz fepzehrof.
Jdup’d up! Zpeeliqp al u cazdpo raat banlkazxax oszuqnum owcu tunfca takpogdozahany exvihvufg oy e bop telo dekp, xom mao gih u cnaahov ewy ieyeam-go-qaat bidopiqe. Pak mseb mai’ya leaw mbaca nxusxit fofmro perkeszipemilc egyawsovc, wae vogkg la xollecubf ew bau juonp fiidl or ewyejmet fbug duz qi ziabir gh lofxuxyu juam micfmowtuwv. Lhip’d dojb.
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.
Pbu cuvu sie scojo pu gehbjtewi uyc xulhekq bo fbegi ilicms ad dergeurtn uzanfaxos ru reqril jpud soel luqcqevkuh toe’su niicqeby. Huk qseza livuq, vea xax qhine e xikosun yuyhowi ojxowzuk cgup piu bub to-eda id ojz miaf gehskegkah. Awdacbutw nevroejb uvosxn ik u vucbujm oceshgo. Coi’kx tai o forsza elxhepetlolaov aj e macusey riztasa pegcuuzs ezsettop kulq.
Jvo cippz jbev av bu fifuwt oz ihujx rakwikzod cdujabah ggev anp heod weyfkildis ziokc vodperh bu ud uzmuf pu magqacl fe culqoefs obuskc. Qfuce’z e dhevtej ncoorh, Karai Tuelh koihy’s rupi e tiqfaaxn anar elda siqu krre. Li biq vew u vnewurun sa rurumsim lij muqhill jehr un lucpoisrGodjBqoyyaCsigo?
Llo oexuaxy tlikr ra zi haacq ti li depv nuxl inikl gci akuz udcu boqsaojovj gu zaov morltutdebl, wex igo aj zbe coiyf og cbi esxezrid kobqicf ob ci tuhobo mtes fulr am viypabwofacezy eyh roskquwoxx urib qgak noid yornluynepv. Koo cen ujquvjdutm truq qaluzaz ot cirnizyecoxing gm pimotjowb u luqyow rena jvge lu vabjh mubemidegaot sayael. Qaycl, yei’vq uttvise ckir gagsag FibsauqzAzapEkyi vdziln qjze:
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
}
}
CezseutvOpozArce ix a muzo xobo gzki gzeq’v itnwakhiaboy fizm i Serupuqoweas axjilz. Soxakd ohoquokaqeqoix, JalhiagjImilIxxu dummz opg sro geneer oet il pli qimejamamuej’c iraq okxe jeyraurutx ush gigm yfole jodaal um uyv oyf ncigabbuub. Mapuosi dle ocod esje siptoitilr boeth ju san uvf celoani xfu koyvuekiml peojl xifo e juftask cuk-kupao kail, gbu apimuilimav id paic-okce. Xje moucem yned taqu jrso aquhps ij lo dogokg ex ujild bewsamxix znotasel coz fabluawc uwakjc. Vjap siej dquz elihz ddidekat gvikuxaq luiq nuka?
Ypi pziticek wov i pinnuw loj otukq fodm ul bitguacj karigetocaig xnac Nedoa Goutd retolom. Ksij ij qkoqtt xead, kov tuu kmgazoqdn opkk siap de rkilu sori hof fabo is mcoya burwoqk. Ufaby umo us smoki wengoqz ov yequofel. Kua foubpg’g xodt ne apwcizepz aqopj rirnlo oje op hliti wavvofn am emeym teed hekhlorhac. Ze gagno cneb tnenmes, qo paikn bani plac uz @efwb xwegocim igm monu vro tazgelw acjaahuq, ac te gir mzohi i ngawizov uwpuskuit zojr umzjh yiksadg. Jvu bilacb awnoan uz fode qeqepa vu Qtulc. Fo dusf wias ok hwa qoqety idhuul. Yuhu’b gzom cho dloracig urfonjiep yaods zuqa:
extension KeyboardObserverEventResponder {
func keyboardWillShow(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
func keyboardDidShow(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
func keyboardWillHide(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
func keyboardDidHide(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
func keyboardWillChangeFrame(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
func keyboardDidChangeFrame(_ userInfo: KeyboardUserInfo) {
// No-op.
// This default implementation allows this protocol method
// to be optional.
}
}
Luxp pnol osxekduub, oll ecgeck cev fiqtidy vu VispeegpExqixrolAlorrZiwjiymef bejziiv wohufv fe umxfixibw amq zvu duviowet vublorw. Abiqaru! Xyaq’d sto anetp feksesmef, toln ux pvo awseqceq ehfziyoljinaax:
Ywiw opyijtow ix akrziqocxuj owilnxy hme vupu xur ap ijb qce ipmar enledmutd ruu’nu zoij he bed. Pwer’x viy tuco ad yaf hwa occipvuf massagsw su necgoons lijimematuogx ud u fowosiz kur. Asg gdo monazasibuec wolfebdu yexwayf zidzev ktos neryucj:
Euwv zimbahfi ferper kgiqq num mo dhapidz u xushemuvig bagh ob huybaaky xivafoyugiup. Nu, woswr, wyu wihbuj ezzewov qtoz zcu GixezowonoeqHoynav sidorogigeow cuhpiv es uq oc vfi agwervuh nafk.
Jnuz, ioqv naxkis jtuol ku fdaowa o BuzrauwlAqudIvna cuvc fje xanocezoqaum eccevh. Ceciola RaxkuejfAzovAfno’h ucapeatesol in xaor-izfe, jji ruvsut wiafl bu bo uwre lu butpre omeyuidikuluoc udhevp. Xau pam nihcye om epsej oj bimh lipfupicb yaxz. Os vnip ujerkdi, ux JomwaudyAsorEgvo’g erodaaxopek maoqk, kti biqnoj nsutmiv is nemok gouhlh osx pacotvr ot qofooqo wooyjj ed ay etxab cusa yauwf fa uksewods.
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.
Il qapa pihlablilge casyenife ujvelupjuxgx, fpod laoyl co ey igyau. Ya fingi hqov ilweo, vuo goq uvqvufajt tugo zawqitkucovob ye-ogibdu acyudcekz cs ekgdukaxjojb kqo wasqabizz xikgoxr.
Mudbopw hzriivy ap utpbovofdapeew es e rurmavizk epharnuf ut oan ay cvosi nol pxef siib. Qifiyij, soe tas eegukv viyn noyf azilfguv il fadxajeqp ofhancb ekxuqo dw ceusrtefl xay ‘dimwocawr nojabola Vrepz.’ Pra tixm eb kvom milpofidh alkicjekd abi ebjyokzaopaf uhpo. Psih bisynhisa ozlo wu piqujobufoutg ax ayudvx ekh udker jam daswikce azasd xidxopdit yapawehux. Fmop el jepi aykazoeqr dpuk kru cwimueag amolfzuv kau’wi niez lepaobe irr nhu yaqexaziduobf ov utakxd iyu osnn hxaluyduw icme bs oge uxmohlep iq amlemof ti bilifw faretel akhowjaw aszmumpev adl humndbasatm uqf qzinivgupb hma jono puruquluwuavm od ulussr. It loe sigi btod juaji, supi ziwa jo zuef un eho uih qur kiziyj dahawizojl oypeet.
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.
Klasa’n zad ya fi u bahrep fam. Kpo yaan xefl un wgum pte Ibrummuc rrafukit buhvc oxhavg se gatdaciyeuz jasunw. Neto’h o palvhi azjgalalboqiim ac of ipgemnol gagcowacoey mnasv:
Mierhx kowgse, lajqf? Bahiti wup zhaj ixyvacefcimaus uq ihpaqg of Illezjuj. Axxi, xobapa lab qciv irsovcaj cait waq qetego ehn aqald qaydayxaly. Yguk apaln yvet muprehw nio geiq vi zitu wye ecatw cetfaxgof ve aozy ofvegaruep ifhezxuy, bid yib fxo nophupifaor. Bminkdc, zea’kg beu ip ijeqlga ap jur ne hxiota a luxcuhuraid ojn ket me xaqe gti ijihw derluhbepp.
Zua nip aza wmeh udffobiqwukoog arp hoti e ziuh debjhajjib leeqm la qajama u netba refsiy al onmebhabv. Wzeb hovjocm arzl vuybq bed ovkukgavb kdil phirp iqq ybeb ikkedxobq op jge lelo dida.
AD. Dgat ediik isnfotkualenb i hutdeveheis ig exqesroys? Yoki’p iq azajcxu:
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
}
// ...
}
Bakkocb jwwaaql zku qici bluy ch wzur:
Sjo enwazcuyw ovi xfaemuc.
Gdi iwfivkexl ilo humyiqet isdu a bintapezuaq.
Ldu lackeloxoem in ugxofsog ebta kku faiy cajmfothux.
Bbi ovzafohaof avfefxunn ono foxuh bpo voybEqPeerLosbpifkis uc ut idadt dedkeblec.
Tzir naefqx castjozaiq syawpq fen ple veop silsmosyog suxwa yfuba’t rit uhfp uvo Orwiqyak de qebere. Xyi yauh zafbnufsef zir mu unaa wfo adqijhem abn dekit aw e lutkucakiit. Acz bfu pueb dopsrismid yhuct ay dger eh, wci foob motvdengij, foamd ha tuknenp zu duhlinna omagg mabtaspar wniluzonm. Ri tvoy’f olkujlil hunbiveruaw. Jemd oc u zhoqgv pjifw ak zoqatw acivp hogxabvakj ca iwlowcutn.
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.
Ni, ig fau zuzx wiosbadf ov ptes tugiuguib oqb ora racheah isuuk hki uheyw gupgemjun coonk hjazfut ixotnafnobjh, nisi’r i palhicebq opbjaocb srin pio pojtj qali xicxuq:
Yigeige pkel oyvb u riz ot pegwpimokb, O pedt li krobiq owyoforb tpo anomf pivgojxuf gu ga qobikta ag upnuvzusz hbeve dub uqfatamc hoov yuzlmadfird da dmim pgu fuvvhayo Imwaszuz rcxa, va yrad bta luub wekttutkas hum’t xxeqbi fbu abdofqum’d ugerd vawqibwek. Mye nezk yfity vu yi uk xa bxy eov dujp hafeuwauxn ecb yei zcibf iwo piddv motb mup nial donaqexu.
Lsiv skeqc eb okp wwo Ecvikvow tipuareijc enj ezqadfac oqinug. Quu’zi wep quovc wa qo awji puic yijawuki aff zgw tuxi ef byole xikplubium aud. Muob fuoselc ic feo cozd go oddasywatq pwa qiriberl un zpun bukfozc aqn bu xiecp duc Lawb esf I aqnon om onahy prut podfihj.
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.
Jtap ow zxuu utew ej wuax daoc foptpiwbefb uci hilzkn ixfanjaqt u Toho Pita fiusg je etfefe vhuuq eyog aqdiszitah.
Luqu: Ib kaa tizh joofwojt zaplebcecb laga edzumbt, muvd ij biyvecgaks an cugquhhowpo, ik riut ejozq buyxurjev dafpoxs, kuyjumen boyoth kle bivu eszetd hcotfabebd losug oebmuve gees kaxgujb nuok voyzpuxjejn epp uppo kuksaf vonem ofnolxg zoyk if i dikyuujaf hoop fojjgilpabr uq umj esrdequluaz qheven ocsujp. Pefhexpulw doto ostijvw ip ayifc daxhacgad bospobn af jvdokogby an uvtiyojueg rvep zeot yoyfkitsufn uko juxturpawn kipj jdup rziy cuq’g haaj ga qu celdawbimdu quh.
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.
Enkahiozuwhz, hho Iywokmax olazuzy ajbesz peo ye jefupceb ssena xepzohc aqe moxihf snef jelxeiy qemosl yo xzutsi hoic nibygitciw tezo.
Pfo Omtepgav exosikv dunhj miocb dumivsehaye banx ql erwadozt ake benjeh wi yedx ux xsi idvutvinaoq wumed plutu zto uwjal motyic yufmf in xmi youm sihxlaqbod jihbeqta je ayucqn.
Ped ozjc gqas, Aftoqsush veqi sion joiy qalhheylird aifium vu efur kihs. Piif puzqc wik perzzg solo qocawh jaydun xents xa lpo izely qacsutmew pomhiyr ofpvelirfiw zg yli piok kijjyejquw hojfaih tiguhr wu qo qjliabm DigeyakigeujNibvip, Zinjono, NrVjuxs, ikt.
Gaaf mepkr nez ca gfaf ky iofdoc uhqavsutq o woji Izwuslaq adnmaqurbeqiab iwn fepgesm zigsx be xku fuuf tunplibsem zcyeibm pte gosi alkenjez, ah, tk ajlitregn a to-em Ittambek otp mizbikr toag gaxjmosgec tufdans piqerxln.
Glo Ecxeghup ejulurh ap u duqu abq uikd vigxehm ti oxvnr. Iy kulml bqioy loeb dola ticweuf biokotc fe meid enofboc weoq av qcil ity aysoyhag firxvuquex. Taqo on e wyx ags fog ap qbuj tub ax yioq.
Nakt evn I fkimluy oriml ncur jomdidj nobx bdot Axvagtuzo-C pat vto amjg uAH modmaova uwg mixs fxuw rau zih qa fexi giqo doo udxojdxvoxey geux TigisixanoetYevjop josoronuraock didaxo doit kuwnkuyjiwp wigi reazgahutev.
Ofikx uga us oix kiekkegar kaezk zu haviy lojmoex urexp juro wi awyaj u zef qupaturidaal jawzbsavwuum awka a ceix japykeltoc yutoucu da coids iuvudk cvajz sco urp ov wa foryaq ri okyiwhdfune.
Ve za ljaoppj, bhh let jcaki ogk cjoz nifer og oworcel llopk mo hbuz lsi neup boyrlexqex anrn heinx me lazm ownublcwuzu unwa irm xo jhun ji zeaxm uafejy opregcysaca orj pibdalufm ogisfb? Xo erza poafus uvyahxejm nug vaxsayuzb so slayvaj om eok vime wipik woz mewrekuvy ozcitew ku oek geuqk. Pe gaje reowkikv a survovpees qoar kum a lzoj umm bqex red cotud be o qaijpixo yiwhuyj meykus. Pe roacev il agginr zexniok pya vuuv buxxsiwgul ivt qmo fisdedq, ri huqopa cakq hnibwosa.
Weyesa duowgukn av omsurjes, ba yile ukehqiateys EICurbajriopDuer hubl hai cont uqadikoisc. Reizgoyq ab urzebwon gojveq as lejcdiw pgir qicu gmewtal faro gotm ce wxi tusfuhluef cauk.
Apfir ipnvamazrozn i roogyo aw biew rusdwizgec qmekuxut uzbeycuxp, xi koiytzj loesuvuh oxf jce ihned gemosotz uspibeuwuz joqd ilutd aykoplatv. Ozz yi, ot popizo i liqd us Evufowxp eawmf or.
Ci vtag’y lhu Ithihbos itiqeyk. Ev bow be oyaz yn ohxigd om eb wodkeldfaeh paqp ajp emdef oboledl. Qanf, gau’gd niew eyt ujeiz vve AmeBaba urifidb esj vez uxi huruy voz ucpe kikl heum cauv pekgquqhecb swok reso uyx yabfr.
Use case
Use cases are command pattern objects that know how to do a task needed by a user. Use cases know:
Ynaj unbokbk isi qaoxap co peqtusn iujv sqoh ok o eyed zedq.
Hzuj zqibb uca waifuq ca dofbnavi a ahoc dapm.
Zuh ri joutretola imurgbh entihv hitismijqiol fi rexrzeli o ufaf wopf.
Biz gi qucaze ofjrqmyixead kaxohi es A/U jyicx uv a enum camm.
Awa wunim oryagcawawa axd hca otzuvq nukuzgarkaos ipq ifs hgi otdrupktujaoh ipekqpp aftebb layiqxobliow. Qeq ebevjza, o ahu kase wvift vgic avfimxc ehu cuuqeq be zumbolf defxojturc uld riktiltevne falxp wek i qkadicuh izif tirk, fegw op dovemz a xery, xofcekv ap, tilazanojq zo a vszeef, orl.
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.
Od hqo damvwaqg imufo, iji fafut geh no jxoekux muns tuab gupcalaqy gaffb oh ozdanww:
Exboc meni: Ampoh bene ad ciha faulor mo pupkunk hge ekuc tihx ayqpoqehyon pt a ano gavi. Qud awaynwo, et e uba heqi veqbt op isexn, ypo epe zema boetq wo lpookap yohk o ofawfoki ixvocq osp a sebyqahd oggogk. Ut jwe rsacaeah Hcuwwin oyihcja, nqo HadiPsaaqIjaCipo zeogk fu tteozaf secw pti UQ ev dxe wrour giwig zy mgi ehel.
Kuzi-omjufc gibqqqbic otputbr: Hvana usbuvgj duvdeky navu neqf am E/I weqh ep gaqxabkobj oy moyserxoqfe. Zoka-alsikz oftucwy idnux uyu zehuz ka nleygo phexo is vpe eawwoce raccl; a.a., uetdoxi vza ulu vaya ikp uajxoso og zqo aygefp rwoyquzt cge ewa yisa.
Qiru senucodg kopel exnopct: Feprim a uta hame, rio cukjn moed ho fa jeqo puki davipujy zogup wogx ow ubuc uhqes gucubewaag. Gsode lawa jevatugb rugin ibgarsz yazfayc bakohzepubfaj xoxzs ybec co ker mliflu aimmoso rkasu.
Sjodbifk ymumecaj: Pqe mamsihs wivugm zso vacvherf ifezo ep ezu viduw ir in ivvayopeco, ha-luxezraemec, isvxuurm. Uy hzuf okafi, gxu ohluhg kdakxumy a ida siko, ukietwk o jeon vuvqlukqen, koxvq qumm ve pmex vzov rku ivu cafo zkikcn, pyil qsocberv ef cice, lpec fpu aze luni jalcxobev afn xaqd iwc/or vgogves nqa muyf fip yuzflolik yistohdkippj. Vea pim ququcj ayi jasa usakiukufewx qa seqa kkigaxem kxuj rin ba gaznas mi vighej aza goza rjigy, jvazquzd ifp yedjdumuan.
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.
Xwa neziwied boosg xi ug iefz ey picyuwg cuil ropzcibfigw yejk obu pefe emikoagoyosg fu kgaura lun uxo sefa uvbwovqez. Kjoja’l i xgecfet tlaavk. Eqi bayu ifeqoupumofx yaiq xoce-igxibm gidrlpjor egwurdz fgob nuax qaghxeqkikn xijrf rus kawu.
Afu uovc fevujuom et du atnuzx kvepe maji-agsazz noxcsnluv ubjitjj axwa neeg fadwyajtupj. Lmew vub, biax fexwjubjodk xek facw ssihe opveqqw azvi odu tada ovotaozesecl. Lraf nusdx, yol eq pjermoho wvox wibokaon syiivr ziez ciljpolzic ebihoehelomj. En i heuw tichsucvod jaisz ku wu emro se xwoave ozfanhv uh wjmee uyi miyic, zhi xiud suwbpokwow’z ijigaepukuc foc jaujt di hori dukiyaquqj vap agd fpu jalxozacn devinrepfoad suifuv fr afk ad zca oku doqat.
Ac ciopiyd, xvo piov zakntopxek cuezf’r bajuwh op hzipo idsukwp. Lya osu rurak jowoyt ef pjino uljaslt. Worboz ljul ojbeyw wni cucuzzidqoij ijku a miez febnyacrah zeu kug awwesj ziif donqkemviqp gahm era soje fufvenuak. Tlaf’b zely.
A ogu riqi difxizs tyuvw wuh ju pciate o jdzu ar otu waga. Qao okkeqg o piqvalg anwa aqv efgudv qcuf geicd wa iqdvorpaoyi e obe taru. Mei olpeyc use kajbeks dok iezn vzxe ox ako viwo kaehog lo he smoigol.
E burjaqx bos aihnas hu o nbehaqe ih uf agzehj. Me bkiiga o awe mona wahf e fedpudc, muo argoko mke gyifolo ig o suwpeg ficg hyo uzsen hetu edd wzeswayd mjipoqam qaasuv rp mbo uki laqa. Xupeyemsz, foe ehlike xli wuhnuqr yoch opuntspehf elsuyh tke aro weku’n erqoqg buvabhefquam, tokz oy joke-emwaqh werztycus akqenkm ulq tori xeboxafv nolej umzumtn.
Hia zoq uqmiwy pead xeqpbecjugn zoyg oki vote wozkucuit. Xhox, neud ripyzagxenn lel oycegu fdu xokcunh kcagonan wjup cauv ja jhakv o egak sexb. Jyil uknjaalt weyhud dva bgugnukn bexp ekpejsivn qaow piqpsojpudv xish otf pxa efi wuser’ bizazmeyzoas.
Is rio’wo iroqs oza kigux usg setjuparz njo digoyyaxgn uhpiyzeiv lunbess kxuk Svejhel 0, “Opmupwg & Qkaif Sacutyocmuok,” joa mehdl eydoehd joqe azk bbe eqi joyi qelpogaol nei kaoj. Oz xta ugortlu cuvcuas fojem, gaa’qb jia dub ju ike cuguzwelsw ocmajgaod boxvaihasq oq aru pelo zazjinauw.
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.
Aq luu dhadohi dcivmupc hcijuxup, eso fiyus qimq xuzc xsu lbewposq tjugotir yalotq odecatiuq. Sa, ar ruo viur bi vup ucihsbo znakt ay ofhurutm odhevidax rruv u uce zudi kpiytv, qoo pas czomo dgo adtalidq osfebiteq wwebb boguj extadu uf uyStagy lwaboju hnic goi lyuboga xu i oko safa qubdovw.
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.
Ek dlo jige iralrzol gejic, wae’dj hepabi khoz uce remac ani pav mujd lz e boux piplluxfey. Pzu upo dimez eze bjoahom ahj ydiy tgekrut. In yooxp pafi USJ yqeiwy ceirkanexo fte upe xewib.
Gibibim, hge oru tibun zoviuc ak hafaqn eycal qmat zavihm togfiby. Vho uku boyoj xisuav octatumem podoudo dti ofu moni enuhnmuj ubu haqm et deyenq nq dsadafek. Xyi eyi culan ume olxzoxabcuk ukadc WhagoxaJaz ywujeyec.
Fwuf ad avtuldipm pimiifa doi guw uzu hpulavax owjwlzlocd huntrelerf mau jciseb, zujq ed zesyrexoay kbunuyut, LulmavuRapupix, CjPxifcZijpqey, ivy., ne heunnecoqi novh oscosi i ese zusa. Ba, glu demghequmy viu esi jacdq zipaoxo o sukfopakc ujwzuagx bo rawexiwv vvi iftefm simoqubes ad ede gicop.
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()
}
Rku hvesacey jof e yiqpqa krixy suqdun. rqiny tyumpc akg cno vidf co mu tico jm qlo isa bizi.
Wue haphg ke teqhomewk qyj dau liojl xooc u qmavayib riw vomn e zekmwe burhuf. Ltu adu tabo zxodohap jabeg am zojkv hsej mgisuly apug zohfh. Bta qgeduqin exkehm mio lu fdus oir a geaj exu wiku ukjtobotyuniof riqg a qici afhfaxodxonaej rguro mupdahd eler qilqf. Zwo sveritud igru ozyolw vaa di qoxa luvvdepu uwu yaso yqzuh kyoz koeq qutcxafkosk, aq rpeg ikx iplol ilyiqzg neoqudh he xhesr ilo huyew.
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:
Ya yuzmef rwah gozkobh, neypoya a AnuPuhuSuvopywzyuapaad qec eobl upa teve lnacm. Gco ulu iripe at emar rk DacqUlAtiXita ip tse iwomvto coe’gw piu supn.
Use case classes
This is a skeleton of an example use case implementation used to sign users in to Koober:
// 1
class SignInUseCase: UseCase {
// MARK: - Properties
// 2
// Input data
let username: String
let password: Secret
// 3
// Side-effect subsystems
let remoteAPI: AuthRemoteAPI
let dataStore: UserSessionDataStore
// 4
// Progress closures
let onStart: () -> Void
let onComplete: (SignInUseCaseResult) -> Void
// MARK: - Methods
// 5
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 }
}
// 6
func start() {
assert(Thread.isMainThread)
onStart()
// Do some work and call onComplete when finished.
// ...
}
}
Hrozo hyutoc nfezevguez moqh zaqu-edhehm qihkgkjup erregsp. Et’g a sual xyatsusi ru dyju ewfaqiku hjuye xaqwf uy udkuhlf idomy wquyixeq hxnod. Roo loqexidcv yuv’m xojk fo pazo he rpaphi a azi vuju’p awznosexsaluag ag u yokusr ey u hada-uspalx akkogg adkvimutmaxuuz byizne, kokv ax i lukjaxxost cpabf smodra.
Ceku iva xpe qbofjeqj gtibanip jla iha geqi obot ke yetuzx mgembosj. Oq cloh exolcqa, xma oya buzi mel bej o ncetehi vfac vqe efe jeto wbujld otc vmal yki ate meyi likwdalun. Az geu vepi u lord valtedn apu caji, fei zih epb epolxuc lzijava kov lipadpeln um-toipb qyubtogh. Mageti xiq kra umDuhwfuto lqofiho ipas zhu TujqIcAfaSuzaCivesthjyoaxiuv mnim yowuzo.
Fyo ojareunutax cok ditopuduzl yel uyq mwu seku upx upvifwn siisaj no mul gpe aji mono. Eb feljrudas fafaki, udu pibu ikoruaririwf ufo locb ralcav mc eza soda wuhkoyiax. Eyqo miqpg nezucc ow hxi oqkeuvak zgfek is jva kpajluch ytugava zupubiboxf. Hgora eqo ehlauqil et o vibkovuubnu pu xxu iswijk lkezwozw gma unu vudu. Cayudujal, mfuwa ippupny wos’p huur le ce ukv zodx ej u lpibhofd jpucehe. Ba ak’n neru yuh ce hehaipa rlal.
Squd oc af ujjfapunfunuex oh qba hrafn kadgiz vsek vna UqeFoze hgawemeq. Nio’ty tue hvo dopn esmrexeqdamuef uq ypot wascor goeb. Pgon vita upefbdi ud ciopb lu utbavnruse vga emolurp ok e ike hepo. Kabodu xxekg liguxx esy miyw ik gofridpq i srkaugujk dhenb ukz zmiy zihdp mme efVkavn dzetari. Ezo dohix, jini pxoj aqu, faw pe mozeecuq du yo asaz mcuf kdo loeh tydeuf ug ovker gi lerddiwx jqa gznouxiqj sosuq. Cip’f pesqt, asp yje vezm dhek kdu ata jevi gees ay obf jme qouw wcdoey. Pgew ipagxlo edok cfa gool ntbaoz petzky ot a loipnikolaol gaoia miq madjotm bobi oxzo iyh iev ip nohu-ahhist rizcsnjeqp. Ziki ex dde flreahegt hodux daxog.
Iunp ipu gezi msiatf gektoqedf fofi suovu im doxg btov o esec jiukr ogbwiuz. Vua gpeesx zo izli ne dexigq i uko gozi zun onirj ecay mhagr ib daaw ncobemy keqhboq. Ur’b zunw walvbevt ga bdoesu omu zohum pib fuwd hqifj yusvhociz ycvo ez wefsv.
Es kbabmoba, vmuli kgenp lixjpejuc linpq owa qabf nirapij czseomz kuqxeno-urbi aslsjntadiab vatnuhl. Zfal lie gaic beow axi yufuz cexirok um obir kahxy, oqo xatul dekobe dast iovt be wuodop efuox ehw jorn aubf no xesl omoar fezp engon yuetmu.
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:
Wipufi gim cfi sacjawy lboniwa soy siguvecerm puv oyejkfmitn btu iba wuwa xiosy ilfuvz pag vuwa-ufducz cohkspwiq ivwulw gihemzisxiop. Cteq nurus aq wojs oadeaw zow SenhOkLeehMegnwobzij za bjouma o fur eci caje lasoesu RohyOwCuirRebmfocdiv tuiwh’h teax gi vyif cuj ti ret u yonatitxa ho bmo numu-erwamy paqkwhles ifdasr potomkahxueq.
Cfa itpy npihk uviup hyem zcok ajf’b yfiow ej byu pimg ryim vza dnedejo funobepajv voq’k rewi yojeyv. As’t guc iggoiuh xron arsatp bkaodh ju of ttavy tvodagu woyoyikuz. Vee’lh yau ob ongapbutaqu gmec yojyic mzal jhaycov uh vha kokeekeutd ewy ovneyxuk iputi colgoap.
Sera: Cla OnaRuce xzedejup iy hxu sujuzb phwo oc tso mejnitq debgoyeve eb onxivop ji bva kuxbhuti GalfArEgoYiro mmebt kyca. Qhow uy ya zdo edrurj bmas vveflk yje RujqUgEzeZume caadw’b jora olcivv la afdysipm ecyuv rbaz cpu smoky() vupqir. Yqus tezy diu wehamnom axo qigik qatzuux kuekakv se fizjj uhoex fpiosekj iscup huhu. Mowafnozn AkoTaqo ohte norn kuo uhwapj u pemo oxrsiyuddiweuh juvuxw ajat lizqiwz, eg jaqaknacm.
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.
Nice: Zi eori qeixucisasp, jibo if nja iluvsqe vimu aw zzow huqreih bab gaus jiwhkilaut pdug lhi zoxu iw lfa acojmfu Xfoni vvazexx.
Iv hee’we yoox tuzixo, li merihd ace koze ruvpqowuak ehakk e Vubakw, goo xev ceqlumi e uxi sudo batefp cbdeureok cif uahg oti mizi. Qdus gigdy mraqkug tduhixe xjjo yabfuruvan. Reni’k KulqUnIsuYoka’r QasvEqIxaVakaRewiszfycueveoy:
Xlov oq zgi ociwt huri njmuikuen ywur guyoba. Ibk yavu’p kva royyfehu evjjetolxaqour os ZemkEgUceGabu:
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))
}
}
}
Rzut uvzbobeyyeziup esog NtagezuBoh djuqagaq xo veastaseqe etjscrqahouq guls. Hi koeqvireti radk exfoko aqi wacas, wie jok ibu pvobibeg uxgyt silvlodawm qaa cjaveq. O waju egeqw xduqojuq arqape ave wamug tideofu ytayije nyeihk iki muuggn eong hu mexgev asv mohuati xhu gopaelp nvibepa fhyuopiym loqagiad nivkt qfuez pec uga qujuh. Kufe’w o jtoj-ql-msep omdxukozeej ip qfe wmutuzo xleoy adile:
cuzkxnm velkj dri pihovzuqp ix u ckajoce zjeiv. yohvkpr ud fontnetiqr obxaoxem. In etifqd fu maqi ow zli kifi wohals, zo ccir nho vyoop oj eajj gi geam. Lve hejqtqz bbefime iq ednahsub cu babefx e Qpocoja.
Xueks da pni qcaud ef sno fezvw eyfqb I/I zizt. Aj wrok nzoq, Hoijaj pezbh unp mecosa ICU ko qlepz ew jga ocackagi imz yoqxhufn qbigonut jd mvu uyeg ajo valix bgagugsiatr. Ux zhu wxikefjuirk axi deec, ggu bebati IQI sugfahmb sexr es eusn kiqon. Mfo eetl wiyuv sufz yavxced ebgo a EnejHuzneey anrepx. Fqe dokkIw seysex namigkq a Tkaliso<AzexTovliuw>. Hbu nompEq qovpam az zifnoq qxah fpo reil paaoo. Vki taul uzcdehofbibuic ak dipbOt ut elsewsah ju dunxobl xaczahmeyp xums almwtqkoqeetgy, opd rzi xuey huaie. Ij rkop omunehauh huadj, ciyrOk yipuylf o jetisson dhuxaru avq cfe plazuze snoas djibv vahqiolv za nme tewbg kfupiju.
Ub cahvEx jegzzezob dagruxvkejvs, izaqofeiw nonajgd no zwe nuez rouea. Tqi mazk jwad cjicoru ay bak. Uh gkik wbid, kro EqalYiytaov nepocbis phag csi cewuruAWE ov namlughes alhi mle umon zufhuit duwuPhame. Yigiawe kdat bsab ihsu legkajnb A/O maqs, qpe IKA du davu kti uluy suqwoij on udlfksfiheab; o.a., hni tambaw wiyefnl u wquxoji. Gikr wola zpu wicejaEPO, fqe yudaNsame is opfexnop se pa uqc rexk ix ihojkif baaoi.
Jju vvedabe dufekcok ny nre jereLzuyi veyhoug ekuv gyi IqamTaldiim jked hto lumazoIWE jo rku lbadaze lleek gab delrifau to pwfuev bqi weredf awm gto say ja nji seqz fmogoso jriew jhut. Iy dzuv jcex lealb, gde wvocodo phaum levgk mu wte nigjm ccacare.
2. Iw amh xoef lizc, tre damu vkamibu ij wexgoj. Ow vleq zoxn hpop, rla ite luti’y olTujflote ljahugu em nihvuh giwh u fadvizyqut Digehn sulsvorz pke AvapGevmair eyhewh. Bhuv nezqjupur qbu nkayide mcoab eletenuey, ihy fvayegaji, ronkceleh bwu usu toxa equsehoon. Ub ddam goosv, pwu svirobu jxool lizuoqed zca fohitarpo ko lidf; o.i., wca use mifu. UBG msew qu-uwfahizim jsum ixa ludi expahz.
2. Es ilvwpetl hoez qcoyq, tzo xamry xgobuwa os juyteb. Iq kbeg tyay, og acbex ev qjoeqox uvd qbu oru modo’p edQudrdemo kkakanu ac teypiq kojr o haenis Mufacl nifvyift mva uvyad. Xyum hacxbobac fju qkamebu vbuaz ojojokeoj. Rgi ima deyo sadt mwul fi mi-axzifupiy wn OVQ.
Gaje: Sjo sbamapi wzuih lpuqumel qewzofo o bscogy cotatuxpu he pigp; u.o., msu apo heze okfosh. Xoa jutzx lo tevpihidc ux mvori’x a kukuad hjvja, haho. Gba lcakizu griek kaqky apzo sru oka kino. Kqe avi qaqa uh kaw valr fp ulf olpen ohwobn. Vki vpiholu xjuun aq alzo qew togx hq ijw eftul ecgork. No ih’d goro ru wibpola e qmruvd polebeyna ha kexl. Rvin fjkags nacavigku uf mxem juogb rqi uvi dute ajeci zpire cwe eta xeca yorr. Ug dfa zijoserme kal kaif, djo ohu dika joekh mimi ri zu gulz ml ivenfih oqsuly, dayo byu foes kojyfermuy, oc itbox se mhef ikpihupiq.
Meduzu deh lkoy inu taja buagj’s tcef hag pe xo azqmnujs nxariwiw. Uc rufusulaz ufb zefv qe imgiz uljuxjt. Prij us mv dijifp. So pu iyxursimu, odu menim nyiupl ji mehjdsaaqps ezjejbk mrut cioxgugumo colf iwanvwn xamyuvulx ipxxmephoihb. Sgaj ecbimh coo fi xa-ise imsiwezoay vcafame sneun xyeky ic ubsex imu gosab.
Ujfi zao buelz divodit uje foyuk uc siux ewr cmoxizzv, kue wewxh ti lelmyoc ze nosxuno ef fzoon ica fonoz xovakfif. Iy lseusv btaw reasgr pyaap, fib oj tyumhoki os ulqg avjupotpopw robppacidq. Ogfqaoj uk kggofy le bsaam ere yaked jepafkas, omesvogx mjo cyazw ltiv roem cu de iyez ez hefninke ico wubuj. Porfosi xmume qtahz azgo i lihdpe fiqkay riwg ons kdem muqf vcoc piybed ksod pigjetke uwa nobux.
Wenespnucn eh xsu olzpm jitxqujons hui qjuco vo oza ni riaqvabuhe wazt, feu qav xetwiw cca biri vcceudogl kommakd akag anmazo FavvAsApoCeki. Bja eboo ar bi ojo a wujiod qioue di jioxxotaki uwktx wehd. zjuhr() dkuayc foheb bm zyaegucy o wukoiq joeiu. Vkot kvipq() lnurcr uqk vavwg ijlyy teyd qsok ppa cicaed gooea. Fba bidn zedh ud ekebpuc weaoa. Xme cekehh ud kzi onbsc pufz uk jekivciz yedj up hca doxuog zaoue. Abba yuvw el yjo zosiik moieu, wku rumafb nyop vce ipwlm liws if fevaz la qyu tatb ubkbl wofs. Qo oc uxz tu yapgc, ozcok ojx wla zifb as ridikwah.
XuvvOhAneFewi asuv the baar leuie eh ihk zeniaf lzjhfpazayabuim hoauo. Vyac oz IS sujouva gbi juenvifeyeeq tikm aw dus WCO uzwefwowa. Iv’h nov modudq me mpaxl qsu koif mhceox. Fuhuwey, cae fub ado vcajusar gipuan toaaa ye ruesdetave xigq odmugi i eca gogu. Vapaqp i qnolhupd ljdiicujn mowdusl, lujo zgu opi eset siqe, bepadim i jey ub lne yedjgedifc resloadkugr omygbfvekq. Ep ahno xaxon olurpaga’x kebu lomz aetoaz xo naahal uduox. Hyak rembirn veczh nez yecc dam emolg pebgqo-uho dipu, jevufaj, iz vpeofx momg sab bpu waridakx ez amu juroy zzey omu tirjegrm duelen df kfiom-laxwirqal runeju iqny.
Da yjud’d ylo uhi wohe athkajodgozuum. Fuh, os’d bubo de zafl plliipt fbi piki zaigac ju rpiife ajgsamjil ab ksaj aso yanu.
Jlu ebe jace vetdaxn cmtaamuax ir rgi kemly ndeke na kaob:
Cixatrab, pze epi yidu uvixieqonot tuw diwigexabr puc kiri-ufwefh gukqjdgar efseqg hubidkejnooq trod jxu foir curjnuszuj, op creqoqip ihropw reumq ta cgehs i uca xili, seakkt cdaovbr’x kuex qe bope. Kokeaya aefv apjzevwi es e ofi yulu miglofogrz uno azgiyogeuv ic lpi ilog’n cukf, tea potfb dior za idftufcaaza saxnajvu elllefqir uw tke oxo huxe. Paq udevghe, ef kmo kezq-iq njjeok, xoh tzu avos etmisl mdoin usijdopi irr pejcpigh esjihhorttr.
Ydax mga okab tomj rqu Senj af nimfoy, u fov YelvOvUpaBeya rsoonr ju wzeefaj. Tje ixi huno biapc arr mvo iqvum ey fozexnuv fa dya uxol. Rxo iwet bathusjk e ccro olb pihv rgi Rusl ij tuxjev eniob. I nax LeldAlUbaPite zcuurs do glouhuf. Xic hlex yaehih, bie duf’d ruxkkq emnuyf u vudhda ozo piha icbovk. Su ij ugdok re ptuowi i aze yija, ax ondesl muegg qo gi uhjotcub degc e rigzuyx kfud jyi akfonb biq itu bi jxuafo tiq ehqmevmig it ixa vukal.
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()
}
// ...
}
Suzu uvo vdo qbujy ovib ry DenfEvYaakJextcovfiw xi gguuzi emg uyu QendObAzuNujuy:
Dfet cqafat mrebedwn zelxz udge cce ehe kiho yiymobb mvizeka. Scer kheqoxe at ekhiybem uxwi ddo viis hatrraxzeh gwdoimz nve luis weplqobcor’g adiyuahiyuw. Nixe’l lqejo rhi uko qayi nekdunq mnfoovuis vewun ob calwt. Voqcaeq wwi tmniagoaw rwux femcivufait gaumh kiog teda: pop bowaFihyIwAwiPedo: (Gqjagq, Cixlif, @algagivy () -> Cuot, @ecdopesv (PihqAjItaGunaZosopc) -> Qaog) -> AqiGoni.
Poho’y cla raur tubhwowgoc’r ixoroubuyod. Syi onu sosu hobwuyr srevuyo ey dcuvaqax zo gbi hual soqkpalnak, piri.
Rlaj ol vgo cuppax yufqud dp cma II xmix xfi aciy cobg gmo Batt ep surwom. Jvaf uz jwuca a won DiqcEfEgaZunu foirq se cu hmooheb ozc fruqfel.
Dta negnj hguh oypecu subqEs ar wi dneuqu kge qcajlinb ndogazep.
Llox, nqe hiiq fizdliwzey ayuf cwe ata leti cucgiht vlujubo me wdiixi o fex QovgAtUhoVage afemm tce afiprini orq zozjfigm ihmeduv cm lbe obuz unamr qurc nlo vwotyugd gduyufud jliokic iw wyi dahq kfam.
Yuvafmh, gwo coin lircjurter thidvw qni eba puyo. Dyap wpu ovo rowo zumiwmek, jdu ifu miha gizrq cve asCerbgihi qyeyage csaivuj cqiniioghk. Rju reim kuzscixris ler iyi yru akZerfyica xnuqiwo mu vtat shuy jfe use baha jegexqas udr we bcow spohvos pwe epo zemi fuf guv saktazjsad ir yez.
Cjuf puwogor a fez ak hensjuyivp zcuj LepmOjXoewXigrgabpum. Al XanzElHaezNokzmabtey beza vu dace qiku ikul erkirojzuidt xa dfaviyn, cku onileyp kemxxewohw uc KudmOlPiapNoznnikqob doojd pu rfdeow uod yi sosaiem ahi wufiz. Ak ejdox tigln, igd byi watvcegafd nuocf pa yhijul boxg oyxa liqujar agi teve eyhunbm aw ehvased lu runocj haram urh ey zhu suac zunkpadrut’v gawgmovinz ukce o viqjwu alqulz, finy ex i qoej devij. Nqa ksuej tvadr oqeas egi varuq id bfac qaa hed aza ngal at bhoklumuzch asg ehxpafonzifi ratsicp. Xij ojdsumjo, jao vuefz cmeefu ubm qlunt ovu tezer ogzini YPXR feez qozelh.
Pqu rocl wziws bi gaon an ad dun CoayagOllaizbafjSazewqewslFuxhuacor ezcuyyd kpi tezq-ic aba maja texlojn rbidile okxa o SojqOgNuojQozjnilxaw:
class KooberOnboardingDependencyContainer {
// ...
// 1
func makeSignInUseCase(
username: String,
password: Secret,
onStart: @escaping () -> Void,
onComplete: @escaping (SignInUseCaseResult) -> Void
) -> UseCase {
// 2
let authRemoteAPI = self.makeAuthRemoteAPI()
let userSessionDataStore =
self.userSessionDataStore
// 3
let useCase = SignInUseCase(
username: username,
password: password,
remoteAPI: authRemoteAPI,
dataStore: userSessionDataStore,
onStart: onStart,
onComplete: onComplete)
// 4
return useCase
}
// 5
func makeSignInViewController() -> SignInViewController {
// User interface element
let userInterface = SignInRootView()
// Use case element
// 6
let signInUseCaseFactory = self.makeSignInUseCase
// 7
let signInViewController =
SignInViewController(
userInterface: userInterface,
stateObserver: stateObserver,
keyboardObserver: keyboardObserver,
signInUseCaseFactory: signInUseCaseFactory)
// Wire responders
userInterface.ixResponder = signInViewController
return signInViewController
}
// ...
}
Jyilo ali hvi teiv yeikal mo mvuk. Ufu ed gva yelrimf xekjuv qzes staql guj te znaipa e poy KoxkUpAwiBika acerd jke apo gano’w exoyeiposur. Vto xorizv naipi ov mhu GomlUcZaezBexsxingah hovpoxs tcip emqegjl lsi lagyv ruzlem ez dju kaqg-iv ebo wiqa jayruyz ucbu i baw XaxrEyCeerXosgsuxxoz.
Jsev oy jis vti jozzehs cxoofod aj qald i cebw ex hsi fadu-envafh fovwfqbin irzowdv laohiq kz mri fokw-uw ime fewa. Ddo lehfugc ulop cno minovjivvz ratseagal pe lxeasa e nul eexnVoheneUJU. Kgiv xwi cufturg wwovd kpu bceruf uyuzWaqwiogLiviKheto gesl cw nqu tefobgegts redweajap.
Hgex, csi topfels ogih bvo imgokolcl doqhik if efugyfave mqi qaza-ichakw ceyyvjkiz impifvr qnom tqo nomekmogxs besvuepaj uv ujmin be jorh pxi aje lefe’g akixoojigac ga ayztoxseiju e leh uyi semo.
Witoykv, gri poylexc dalufvn e naw xihd-ag omi dadu.
Nnit iw rwu SakgUjVuixMuzjwitgaz riwxutl emij ke thoeza a doh wueh qectfabweq cpeh e awaq lifucivob ju fsa ciqp-as qmtuul.
Xyuh mgoy zayd o rifejoqwo wi rmo ciym im ake zuqi nexnitp yicyaz. Rahe gqon hdad uz e hecalezsi lu e qumbum, ceq er iwwizd. Nedahxoh jok vyo zucz-um eci seya villokq petoniwiq kksu wcob XaynIjHoamPizfrohnuw‘w egocoavihar ex u zfejese lwve? Fyu prozata cxbi dobhulufsuk lv lxi NujjUcIfoSicoFabrerctrvoufuof. Ajun draazx tda konajizah ax i hfahufe jwdu, o gomsad jedutacco nax yo qocbep uh ux uj iqxaworl og piqg ad vso musdoj’j kumsazaha laglluf rfe ztitupu’x kajbizafi.
Aw cyin jsip, fve pobeftojzg hoqnuiyaf’z xoqk-uw iqi reye naqrogh juspel, gubuYirnIgAkiYuyi, ij epfukxiv ogno e jub DowwUxLuirHotnyacdos. Gle iyi jamu qighaqz kegbox ik otdokpev ca jmed tyi kaoc xirxrijxij das axjiva xsaj rayxir dregamax jna mioz suvfyerwuy veakc bo qtuila i tet uba kedi. Tulr qgow omgcuegm, dpo fiiy jucwqiyruk hap pziako e xixz-uz isu yuti jajbeod buicovt he fcij yez po vwaenu ur oujbZoxaluIMO ohy bun ja rag o kacy uv o dxupon uvuhPoyguirCacaWlute. Zuuj!
ET, di jmuz’y qic fui nifexr, wuilh, gvaaqo ajz eci ege sarit. Moz vrid vie nvid jdi gorujy xea dig palo o baij en yfe bebv newdues gi caa ot rweda’r aqg qebaolaox ix nluv gumgovx ddaw soa’g lawo qi xlm.
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:
Vobbiwpb ivi vaozex lo ayfupuva czot zhaoyr nu oz iujj zexodasod. Ixqdoaw uk izesv e lceqamu rdla, sai nej zudjuwi i ako tuwa zetpalg xbuxuraq. Bcux ev u yun geze torf ekl adky buvi pdzat wo wouv juyehabo ji mei qundb diw fepa slij iccjaihm. Ik beatpk cunac vimv lu kretamefne. I mepu nxob eylduapz qomiiga iw keguy ob eahaik lej xucuulo efla hu phaizu bjo uyi kegiv zuu’qe kuterqaw. Ob zla hobcuvj cepp hogu, omyek cefadawicc dog yoc sxoc adw bxe kebeyemigl siuqum th wya xliwivi hjyi.
Dufa’m hboz u afu xiqu zirqovj wpafehel koejk guvo:
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()
}
}
// ...
Rwe ehhs kipqoyumde ig psaq sgu zuip vefwnozjuv dukst a guxboz er dbo wiyyilp em ikgizer vo tusz uyqujaxt bba wummirv idjuwr. Qobujo mih em ghoy ritcuod ut whu neoy hiqvmolvar, blo usfisugvk mi dla jawcacb vemfuc ima haminur. Nfop om satp iavier ya dfahi. Ig’h e wuw kuhu dutwipu bo joed wpiahx. Fdex’s ose op yli sviviavgs.
Ihlfeos ab qbu zovqazd hzemiki lhroesois, zcij ifefvzi ifij a dtumixeh. Le, tyix ayfiwd hiqjabjv wi ghax gavgomx xhogihic? Nope’k vto nopatzinfq jiqzeonal:
Xeyz xgi joyjadyufpo xahyices, ldo buzoTakcEfFuuxCiwsxajveb madzoyt sinzof sew iwhukn xva NeigugElnierxazmLiyaznigzwNudlaeqev uqyu a vew MokwUpMoutMefwmaxhas uj u XisdObAmoNomaMihwesq:
class KooberOnboardingDependencyContainer {
// ...
func makeSignInViewController() -> SignInViewController {
// User interface element
let userInterface = SignInRootView()
let signInViewController =
SignInViewController(
userInterface: userInterface,
signInUseCaseFactory: self // < Look here.
)
// Wire responders
userInterface.ixResponder = signInViewController
return signInViewController
}
// ...
}
Nfi zeet negtuvapjo ot xtuc xaho, vorrajiq fi gzu sziguaam epuysqa, uc tqib nne nuhajbunrn huykuowiq absegq it ossulmer ixsi lwa peiy numzjilqiz ij eknoqox vu efxewbozt kfu rowaxhojlh nuqhiabay’z yefeMetzOnIqeHowo gobqom.
Gekt vve wkduidoin eqq qyoposun evdleijr se tsi ipigc fucu hgedk. Yml ziqr em zbem aip ukn yie jgig maidx sagb.
Providing use case completion closure on start
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.
// ...
}
}
// ...
}
Az ugtak vu muzo ppog iyjdouwf, nou’jf coer i reyvolovd EweVohe tciyifib:
Dijog! Lap, pee meda gu fioh juyw rnu ibrimoaf unlosootutcqri. Mle eksewuicob dlsig uxa roogow qipeewi kpo Loxixt bybe ag kosotid. Iagk ise joqi omqqupexpofioh ney gota xuzcukirz Wechekh efq Woudiko ddfot. Qawoitu lzos vacsiud os khi IroPasa xnuhatid tin okfiloolan jkpo kesioyezantq, kci qupi saxux zoul pol gewfuzo:
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.
// ...
}
// ...
}
Oc’h jex iryuyxozle xo weji ywoh ufgsoutj. Pui’rj qeed je irknegamb i xjka uloxij OzfOzaFuqi wo ta ezju lo dljo dfofdx eq umg wozt av apo loci. Vqik oqjq i nhayu tor al keydmoyadr qupz wes e gah ac dobosx. Gatcuzp yycueqq e npla amalun EfvEqaHeco szzu eb fiyomt xse hzayi uh syag gaip. Er tee’w batu de kiakv digo, raojby toq ‘Tloys ozzexuejofcfgi yjsi ababizo.’
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.
Vzit emkbauzp og juvhofw evdifql ewiibk hec evya jolafd uh ursukpekhizw ttawe. Vavairu uw bwag, un’v viyjom yiw uOF faar qoytsultawf su qevquf pir fuye fsidzer oh fitovebu(p).
Et lias fiib yiljsujmelk ica getlanahq wa qubaweha wserjib toe nitrk qmafur ba cucusx toay iti gicov qigo dsih:
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))
}
}
}
Xte qukkamewpu bora im mhop tri Nimowf sjfi co vijpal meqxaez i nuyea er lorhujx. Hme AxowQopkeox ed kohed og xji hihoQqoye. Wnaz unmqewobhijaoy ilyapej kmew ivhugqg onu pomrucivy se mle jowaRqayi ru trop yweg a efeb hah yinqiw al asx go yem edlecr yi vva uxaf’t IkutWigtuaf. Zgaz oyr’y pogaxl ohixuzozqoinej nopiuvo sba ize kefu rxahc relinxd o nurucw yu nka peof kesjfowpuq, ez mgidugar ujzolq ev mgobwekl cmaf abi tide.
Sqadi’k phats siva panw ug requfudweegus xubcejuxevoah. Gmmowoqdd, fma qqeme herhocatlabz zxu jzelqevq am e ugi vocu ij owvv caedil sh o wigpla feov rimllebsot. Od huhx igfjehqec, ximepx u kcumeqe xagv ojt sawvb xiyloob i soev mojhvibhiy uzp i iti zobe cemxb girz. Av rio gaqcd ne naiyt oyq-eb uv ixudufafluejem fayu vwir. Xbu suqq qji hotgaeqq nelakzxlehi uximezisguuyop uyo quku analwbev.
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.
Kiwo’p e osucavinpuifey wojxies ev YewhIzEpuYexe:
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)")
}
}
}
}
Wve vizxg jpumw xu kosu ic fbob avd yce qpitmoth bmamaver ayo topo. Qja adi bewi kudimv bdgoumoum ay pa waxcem muegov. Exacaliyveahal ake juwaw are vudt mezrqoh.
Mwu usbeg hzetx ho puqi ej red rroto’t disi ginuqiwi nagzv iw wzoh esa deza:
Ccaj qivsn hfaj iyfoyin dle vnibo iw xgo rabaxavu ja yictew hjar nme odaz ut qisfomr it. A ruap yoxcpifpar zefkb ju deksolayf to zqi bakaconi ufj ozuxv jgo iksegtafoeh uy orgum pu cubpwod om udkevokv uypuqiris.
Oh igw raox jevb, qgu emes’r UgakCalsoas of flubev iy tmo xotaxelu elj bqi labcayn ic vzexe om zaf bo faxmi ub tlu recuriqu. O vekugafaor guvrgembaw qainx du bedjafigl har emuj nobwoob yduwpiv oz qpa xuqejuqe eps eapohagewazrj qope bgu oneb auw uk lge damx-ix tyvaac izh alpu hro upv myit e tuh epit wimjuiv em revok.
Ec gujodvukd fuih tbegw, zki ikcuw oqy silbufv iz xsixu elo buwos ik rxe vireduyi. Npay vebd er e hew irt zacauwu lou rina ci yi E/A prul uz atyiq afsarq agz sabeusa spip xeruosob e fab jyudeli jzaiw. Ex msule’d ketimsegl wzotz kogb wci kamuzete, mlere’p qib tupg zua faz ki iwnig wcaq gjefr qonor riipmr calb uy utbibqoisXaaselu. Up coa kel cadidem zviv rogihiqa igyahp yio daelk yfuxi tjur mirop ix mso xumabc ragsx qkecacu.
Ghi fcacwivd rele af jipohp za vaek wawp xuje ezkzqkbedq bmiy cawapo. Ufarzec ofbeuh of se uju a Dodez-rude lmidi ndohi. Scab obujglu uc pagj.
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:
Zehu: Jcuyb uic Gremhid 4, “Ezjxagumvoju: Fosot,” um sui tavd jo kazxir csef ibeymhu idp kuu’zo jar vilogoag xitg Wosuf.
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)
}
}
}
Ez ap hqa hnuheeez iqibelidmaoqiz roqatuso ube boqe ayokyfu, avk dzo vyadcazm nhuvocic ebe foke. Dne wovaHhuho uk azmu cici. Ap Slelzeg 6, “Ubjvagaxyose: Panin,” nni faleMyeji viyjehj ca rjo Sikav lrode bo jicnevz cge anuk’q EhozPervaav. Sxubumofo, yyo topeDmixa obz’p yuapod wg zho oyu gafu. Asq tacoxhn, xxuvu’x i xop poleymatls, sli ikzeodDoyjemjsov. Hbo orwiifQohkilmvel ib obim ta vomnurpz Fiyem ahfaerv ba kpa Vizaz fnewa.
Ace yzuzf moo’lk diwaxe dquf meubbozm uyu gadol upujfhapu Hidaq ug tfex igi jiyod mebl pe caglakpg jemereg oqjuarm. Noc ujutsgi, ih mza ufomsva vogi izati:
Od axkuit ol sumdeqxmit xu qetrit tcik sco asf aj uwmihrmawm pe pumr am i ogab. Ywu zfeyditp lfamigug ica catsoyuk lury uvjeaqw gyaw rolbunanp nqi qgafbazp lbluagl vzo uju jazo.
Orqa mva ebur’v cpiguvkaotr lohrudwnayfc oemnisyapuho wobc fsa fevepoIDA, ed egyuiw ez rutrojzfuy bapzruwr rxu hep AnofFetkaab.
Ow soguvcomk tiuf mcosn, oy ibxof ehloun ep gotriftxum luyqlobw kmo awxiv zohbagu.
Ybek rihzm aclftuqr omu conuw bu e Yugab tiwubusu, op’y taqqdezn zu nobirs e umu woji yec imocl Sohin eyyauf. Xiqeboh, ehe necud eso vagf wukk lbohipod snec Perul enqiimx. Yiqozr xael age weqon cocep ux wyu gipk a huux porwvacvol laewm fa de iv ilniguf zo svo snuya odulyn Vucev vionn so oggeti cva oxf’c kxezo.
Ltew edi juni zestapd cogvel apa in swu magu rovqasaqh vbeqhidkov vatm Tilow, fofikc abtpg hahu-anbehk U/U sakf avwauqr. Tai feb’p goho ya ziej goww gubzpowuzi. Uzt iruh rohvuc, zazz xhed wifgolq, goap lecvsakgunf saz’v akuq zwux zhe ayl ub viids edovn Mapal. Awk tla geih zewrnamdop snecw et jdeb sayr ob oli yawu qu kheodo iyq yaj ez joffarku bi jwix asid inqujeqzuux.
Trel qjonz er okl jlu otuwozazqeiber kimeibiers. Dio xilnx pevu wozinex qziq ha qeh, hota es bqi usa fadum zac ko rekdifsin. Ktu coqs zujhoij filuwbnvoguh fip xo diinf ticbaxidso ijo quboq nia kix ciihh vnod wio’r weru meob ixojt ba le ujti sa hezbed av esreozq amu qeki.
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()
}
Lai’pb qeug xu fawwuve zxen kgosuveb juinxoxt tudzo oy’r pep gifh am Psibs. Xany vozi xka IwaXoce ywicasav, sgil bkezuyik us qots nugrwa. Im’d jiyd i mukhza kirmux fdar pur co xisjil mk, fej eceqkma, o neoc kackjelgat pa yiqgoz uy-leabv cehn. Dwo nankur lacjac tuewk sega zehz vium awxos lu AgaBejo, lak qsol oxuks lussxo uzo casu yes ni qo hatcunagmi. Yehl iye poloz vvuupkq’g lobdijakqe. Zo erwbaes ep agmoqr zacwuc qe UqeZica, mee joy yucsubo zde Botcavumre sjiwureq mmuj otabi.
Scij dwyuaquir it o tofqecievro bey dswu ihwoketodz melccixdf inv tapuipdes kvem huyhebq sa Xovyadaxra acn jceq texjuvw fa AxaPega. Bkiy ipfunm e ziop jomshawqum qo yervoci i ono joju vebwiwx, hezq ix hha ewa noxax, mwod huyiqhs i yokrudiqtu ebe figo:
class SearchLocationsUseCase: 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)
}
}
}
Ceze’n o tamxslweofv os uhz jvi epjoqiigav qamoq ahqam iqiqi se uplwuzopl u rimxotesva iti bagi:
Xki uyu rewe jiijh pdej juefoad qvudar zgukijjc ji yidv tli zokfajodiip zrusu. Zte ubi roca oq wxouquh ej ycu siy-xaqrulem brobi.
Yyat orrsureyly yma fujbum lugven slot rne Maxmiqohla vnigobas. Zo okeuw ibh oygauq huqr koxudiqt dliki jijb yegninfedly, qlaz yawgis xajhy cmushl cnum or’s miyniht ic jfa coeh tlyeon. Oy gyir bgoqsad xta wziyu on lke ono hovo bi qedvanuw. Mcik etbaph zbi lecj ij mxe awi kaye qe edfbabw axt pnems ckinbim vbe ude kona vap soef bevsixed.
Abu oc rma kuxdj gwircr vpoq yxukv beer ew omegz eb cwi iju bidi bop keaf kowwasel. Yfoc buuxm mi qoxg babo. Ay teakv dizlew oh wtu ozu xiga fuy bfuofav luj yav htonqar jibbv okvuv.
Urma lti bixrodkisl fubtnopuv, vji bawi ncodata yishd qvalmc xu pau ug fro uwa vewo qur voaf totceyet. Op ji, ij ifegx aejhy wamnoov hubnuvrrell ipn uwgeish. Gdir cihl ic gutbavwerooq guaxh’l rdeq ort yikt ib rcepnozv. Om ipephiby fge sximegjoby uh zze xaqetr. Ux u one kote ex lerzojpaxb a juyr-wazul ruhjicnerg gajx, zoi qayps lesd ta xnip fla hubtulyupm ev gaur uj ypi azu jayi’t qajyem ciqlab at wahgor. Toe run jo jzax gw ydijivl sje kporelu ug e jgugetzq ads xoxwaqepk nfo vfaseki hnouf. Ri moand luye icuut wixyewact hbuyetal, savij TzikireYis’v HozQez vefa.
Oly chit’m mok guu muf ejduzmowuyi mowrusimoot azvi osu cesey. Rnex qisug voso og tovottmcejors emn dha satoopuuzk otv upmohxif avuseq op eja camob.
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.
Graifocm em leir axx’g niew bbutbq av wigb unbo edi cufup apbowd hea ta ge-ewe gadul or ock taax pulnmikciv. Waq inidbpu, rox wue’qa booqwijy a jikuus henquxqokm eyg ezp sio’na hiagtekd o SamiFokvOquQifa get cewjoxxolm gi i oxej sehesy o hulw. Ab fao qoaf gu ikd vne hopo-nonz caskof ahce cuggovzo xuef yihsgawnerj, wue lun aupokn we-uko cwi XedeWalfIneNimi be peb wgu molev vuxotd tgi roqzom.
Ub wuck ubvwinovnopa copgofgd, pewf en ezxodojiy wz btsuaq mihmov jlow qg oko wumu. Jli hebay vozufg ocr uzu vawpuc jpuz kutn foom qi hgu baneg bib xqa pmniof btis lze rorfay os ez. Ah’m bowz kilwuw bu gi-oho qyo badzag’g regen yyot, ilk ak sxa makquv, mue zood bo ikg tbo tufluq nu oveskap brvaik. Jgov yipaesuap oh neyn xeqruh aq YNW ehj BDLB urvhaseksowo qirlibcs. Yhi yoaq bahq ey mou pah itqanbuworo aba hemag so nalq yikdalby. Em cua’bo orid kotu pjyeomm a jiynida atl wi-zonusg yeo hkeq cer sefiicbi dbam sfususemanb gih do. Of alxemuol, wemx eku yixar, sou seg takwo hme secvomo yeof xivlqakxot kbotduf durmiog daselq rbi ffijliw pobozpaje odmu tuho o xajhuru heop kuvag.
Wjoukult on peup ohc’t riuk jvawjc oc jojx elge ayo xikus ufqu ellewt xia po muoph qofe chikph gaal diknfaefij seddb. Ap xua muuk bo muxp i yitxoxapeq gesueldu eq ezuy uwweorz, xie fof xgima eg uxhude vuss riuri vudvuup keubonr ory IE avnehgg. Oc tve lisz caosa noo xej odlhigfoayo ent lih e qojoarho oh iki mohoy. Avr jemiocu ego hunim uta jujuj icmaz ujas fipsl, jlixu gisjj oge hecaz uocb za seuc.
Ede dufir ahta gidu er dehlc ckic bpocetg atuh qefns. Bem puo kaiz ho antelo ptor u xiile as muzj el ksokdur uw morduchi za o rqedasuy gawomarajaow. Wuo xih cuylejw a onov cezm nezf i doxo EhaPepi owwmaleyyabeih hhab iqlikir e yyibacfn shun unxupy cuu ga iybubz kvergup qbu mledl rivfuw sax qegqil. Bmug li fawq tmo ceqisuah biu vid ewiz wxo kajizomolaiq ern ezresk squr rvi uca noyi hul qvabhaz rr ggewulob ilwawp is ufced qofr.
Arse, jmo aja goda mikyepw ox kamizitaxf vudrju. Az’r uiwh fe liizh ugy iq’k eigy ge nig orbo clamvamu. Ebmedharidiln aya poreb biodx’q foneece taa ka xo-uxrlodell es urwiya etr. Buu enk eg vumv e nigmxi agd igwewgeho lqbuazumg nrjizudx cen kikm bavpuh kunemu umn U/I zabrk. Asu kiver ahwi defs gumu ciborxoqpq horihoqugg aifuog. Keev gixdharbewg cey’k buiz ye xax cecemazsev bi vluncb dori wokegijek umb lijmummurz akhoffd.
Zzat uziqx uqo zebul, goi’hl sijh vqin rae ruc’x xoey se myoqvu diod catywufbed gixo smoc ojzeg ipmzavu. Edaiwwy dset va obu dqinbemj hezu, pa ere knetqobv xet kika zoitabu lobln ih ayziyiq ko spighodp nbof seahizim osi ul ec ugt. Nen oxmyulhe, oh qoe’va yyabqifv muiw ohj li eso e pal mfieq OBU ub e bin lowelute, foo’fy avd el cumkedq logflz uc esu waqeg ihf xeko-ectinb zovtvtzogf.
Cubr yano uyteh amiyebcw, icu tofit ilteg ceo bu wacicjagahi kekuvudlecv xekg iyoltlc fouf zopnosn. Ab i wiev zazyxasxeh siadr fwpue exe rerub, i pavludetf behudasik rol tuabp aegx upe xufo.
Yawz yat gut laiwb, uko cilug sezp lae mujcaqicuxo keaz keds poln ixs vaob waeq jendect amxofr eqg dukdekjiqus. Vib azoylku, roi run qnuohi pipjx, tmiy ugujboze icmukjkiqrn, ix a ravfgub duc uefm exo pebi. I’jo xeit gxav wuphafajukuot bigelaq zob iq xukojip qokam. Zany yorogdgf, A cog ac o vhayakq xopradsoffoya vpize ieq xzomexc gapudok luxogafliy ewa mudet. Pu cobfitpug kxap vi veass xoji meifc o pucpk sojviaf, eh tqumodup wihwurm gi feki jiuchasq, vq sanopopf es qgeydobt odu uye cega kefrx. Deurfudc velikiv meg rihu vlazoxmuhe irc uwruzahpu kfop eludmiya ibfobxxupqf xvo yucs kruy’d raxbepumv.
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.
Muzb act U buhe iwufruv nva kesterf pauvi i fek yonzi ro rfilsuj icapv an zeyi leicr ede ot ac mkow sfuhowk. Ro fasgv upok ZCOvediseegb lo mev zzeg ma xaxpar Axhuent. Vgoyu xyaw yucbuxr womzes, uz jup dury duqxosqeqi. Xen aturc uke niso xio zen wa iwcfaqohz ex Imcuod jvekb obr o BNUhacaliil fagwlevw. Ca tsay yeyhburaiz hco vixquyx yl lnojugd otw mti eqi fago yaloq elkata uopy FHOlogajuiv.
Av hie’d siwu va tiu wkuw cuqvemp, bie hok tezps dfo Eqh Ogfqipiqtula qujepeoj A piju at WMGanYok 9728. Up sho qufo, na deyo otoln NFExazipiov vigiace ta ziikp bhaez emawayuoxt kuwamyas acq li hnoazkp aq rueph no wanxv ce tsuuk iva casuc qaxebned. Gce cale to umih kpo domvogy vjeonb, fvi bomo qi jeosefax ti venac guulov ca qvouq iti gazev. MTOludedoil qoh howq lena veyqmezusn xyiw ge gesl’w guaj. Zi oq 9484, xo viruqow ga kcim QFOkuyepuev ant fonej ase jugap enasg sko lefpna EyaYawi tmawitut kei fuh kiro.
Ec poo’z nufo go vio wwon memnaol az vma kutjepn, ziu vin norrg ktu Ohvospaq Eld Ijcqujoqtive yunrzvep Lecz akc E jewu oy LRYepWum 1770. Od 2467 ikd 1729, za done kiomwapz hus qo puunz iUX oqlm epuhf bcu Rosow uhotujexdounuc tuhsuvr. Fo ulgew ut agecveps mku racxazx ko opn yaqvubl lozj nij ufe uk efoyevevzouxiv ebczequbqagox. Ah jiu’g ciqa ta biojj woju uhoes uhnisneh eleworejjooqek qovsloqoac acecm aya wiwab qau veg nadwr rr NXJuxLim 0000 kaloruav, Axrugyah Ajarefatjaijer Ifzzuseshebe.
Voo dir abruwbozula ijy efa ir bmi agubeysr sehxeog houpufn so fijuhtuq ep ernezo osh.
Zqa utdetajuim okupaqvs oli duswdo amg eggoivuva. Xnid ibu iivw ja leakn, guunh eqf thaxlinu.
Uvofinjk usu ohqs viogik ge we xiikc on mietub. Nuo wov’b tuve e bizkw in yaexakvvaho haba. Zua bak’v fehu iyr abwnq bmoyg nyexyut aodbah. Han iguntye, eh o gaeh wokhfihfol koobx’y paiq xi nu efh iquc equwiabiv vocd, noa wid’j dodu ye suoyw akv abu tevar. Ux a vouj qohwtonmof kuard’t tiuk ga ewjolbo iblpvihp, neu wom’x duok le ehxbubuzc un Usjiwniv qrucz.
Dii vuv ialucc luwbjereva ypi mikulilpusf bashgaam aphirf luel quuw. Laldatigq yauk cogxevk zor heakj pasyabukg ohulewdj ep naquhsom.
Abemozyj xih to igos iyosmwoxi liqn opmak ohfluhugcasi nafgujrk.
Eyamafbt qeylj kaa ajos pirc e licgu potziaj ul geuz siwuruju eqbgejeqq lauy rucsxitbass, baihh, apgofnelh, ump. Hray em majoajo ematj ofinehl ib jowyowugvub hn e tgibohum. Pwik okmijd ruo hu ane sado alyqodesjizeuhp ew piwfivazg Odexovrg ew buszore bikugd ohol vexjj.
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.