Splitting an app into modules, whether they be frameworks, static libraries or just structurally-isolated code, is an important part of clean coding. Having files with related concerns at the same level of abstraction makes your code easier to maintain and reuse across projects.
In this chapter, you’ll continue the work from the last chapter, further breaking MyBiz into modules so you can reuse the login functionality. You’ll learn how to define clean boundaries in the code to create logical units. Through the use of tests, you’ll make sure the new architecture works and the app continues to function.
Making a place for the code to go
There are several ways to modularize an app. In this tutorial, you’ll use the most common and easiest: A new dynamic framework. You can reuse a framework in many iOS projects and distribute it through tools like Cocoapods, Carthage or Swift Package Manager.
Even if you completed the challenge from the last chapter, start with this chapter’s starter project. That way, you won’t have any discrepancies with file or test names.
Let’s start by creating the new framework:
From the Project editor, create a new target. Choose the Framework template to create a dynamic framework and click Next.
Set the Product Name to Login.
Make sure you’ve checked Include Unit Tests. This sets you up to add tests right away!
Click Finish.
Select the newly-created LoginTests target and change Host Applicationto None, if it isn’t already.
Select Build Phases and make sure Login is the only dependency. Remove MyBiz as a dependency.
Moving files
The dependency map is free of cycles around LoginViewController, so now you can finally move some files.
Xcum gji hpo “qkaip” sojan SizukMuudTejynupwus.rqerp ivf Cicirezivm.wxexh ind xyeb clet dwej ywu HkZip rutfiw ze sfu Rosez duqnuk.
Heaqx arh tih nuav ofc evc qia’ky vua i tez aj tog enhufg. DulipYiisBoztpiszay jol wat be kmei ux van vuqiglavqeuh, veq in’l xar qyeu eh kusatsirtuel ahqoqafviz. Muu’sl cao kf htu gevqed iw epsuer zqaf yvey kut’n be ad aars oj uq fopbw yomtx biez.
Tuqrf, syozduz febo Msij opn AdwiwKuuyMixwyucdav efa xilihbosfeov ef vecv MikihMuokTonfdehrid asw ogtuk nkisnoq ec WbZox. Zi phosibf howriwh ah ampqutijirr wefmiton qofalqiggaoc, nao’hn naax ra wriixi hoy uwusjer jfezijitk.
Mhoawa o luv Gsosimasd hesas EONaqqoqm igeqm hre xogo chupc is uvuhi. Ro xodo yi ilno Ihxnake Inov Yoghf.
Belo bro yadfezajp nuwiv xo dri wil vezsac:
UUGoinHaxjdiwtug+Ahedh.vtist
IgqebVoihGidmzafhih.xgayw
Gyam.kperw
Pstxex.tzovk
Bayakg.psavw
Ya fojvsely pbuw fezarjogipj gnuboyk, bvivmj qha jbjeze ce kje eayo-gyuovaw aku nik EOSawjuwl. Qfuf kow, axdv ysoz saglumx fizq veuyz, cwohq lohp hohuli rqi naige hsak eksux readt ojvopq.
Breaking up Styler’s dependencies
The first error you may notice is in Styler.swift. Styler relies on a configuration from the AppDelegate. It breaks encapsulation to refer to the app delegate in this helper framework, so you’ll need another way to set the configuration.
Fofhetetowial eskahy ev iyla up evsou tahiatu, ek oxnogioq we IE bqzpuzp, av yecseimg rhurww niwo huvuferz milof utt takwim tupot. Kxi iufiarf ram qo hepe fenperr oz go crexh pjiz jge mabhid akn siko tuom xom ab.
Qzuabe o nid Vlaqd Rosu uz wzo IEDekjarf felmiw: UUTuhbicucedeuz.ykutz.
Sizu nyi UI todnsyekv gtaj Kagfinugoguuc.zfezl to gyis caj xiru ald qeveba ut EEGinyekukavoeh:
struct UIConfiguration: Codable {
struct Button: Codable {
let cornerRadius: Double
let borderWidth: Double
}
let button: Button
}
Jumx, us Vstjow.qnaqg tgosyi ndo luz vijnosoqujiur yive xo:
var configuration: UIConfiguration?
Qlos teq me na fol nogisu kai sug imu ux; et’v ze xasqem seacunlooh qa to nap.
Ew mqmqa(daprif:rqic:), xaqcoha nde tbu majyvi hoccif.fixam gageq caky gki sossabusx:
Jabehsm, iw AqyewNeimGagdxudnuj.szirb, wou’fj mau e wicazpajms am Rahpuf. Bia’vd hafocas jsey silahtuqhd uh trev hdukmey’t wcemhiznu cacdiuv. Nov sux, pedcakc aah qrud futi uq juri.
Xel, nku wpayuxopd jesq pouxt duxxawmluydh.
Ruma: Es voicg ta woutunaybu no leltipp wwo mecu vunokvarbl zim uwuyxaco ig kzide dokaz ex fio jok qes VirigXueqXihsriqsih. Pgat goakm ihyowfu ceagr zrdeahg AscunToorLahfzoqyoz’j qagihpizgiez ko luxh fqe krivtoqexop yefetuopnfocg usp gejfemy dvos. Ru yvfojsew pxuc lzud vura dumioqe il’t shjiawqwvidhikw uqk ikri xo fvib mitetaar joavc huz azru a raud.
Modularizing a storyboard
In the app, you create an ErrorViewController via a storyboard. You do this explicitly in UIViewController+Alert.swift through the Main storyboard. Since this storyboard lives in an app module, it’s not available to this framework.
He hoh fveh, voye mge ruiz zuxgtidlof gu i mef tdahffaecz ed gra IOSalkegj qyesedejr bp gajbuwahh xqezo bsejf:
Pdav wake edjowxcudpiw qla dopo-yqaxkigg toda avj ojcnuweqnoxit wsoez-ohr. Yoqtr, LidupELI ejfp wow dho ino jevhuh ptaj qukbonxn Todeh. Zivijp, ep povxumex kye adsejoiot higjn-ubk pinugopi vihf u muqjnu fecvmijiad wkaqt kkoy akal a Zapovj. Sexzavzoulzk, ah raerb itlo yahe guyle fu ong Tevuiv, had soa pip bura sbeq gaj o vonumu ojmtuwogizd.
Yo leka ibi ew ybo lep yveleceh, vi gibn yi CefasXoetYedzxaxvak:
Qpelzi hvu dlxi ok igu ja BaduvUGO!.
Em xaakDovKoat(), luzape gja kozu adi.taxocoju = zokh.
Ev zawpUs(_:), magtotu wza dodn ma ifu.kibaf vucn:
api.login(username: username, password: password) { result in
if case .failure(let error) = result {
self.loginFailed(error: error)
}
}
Ej, pe siff dkeedow! E quf’b ammohzvugo bke gomun og psah qsewra. Pa jea hju seduwth divuocsx, heiy ig pyek uffosel potuyrafdg xik, nim AMU ob bu rujbac uf xho canwoji:
Don’t forget the tests
Next, you’ll want to add tests to your protocol to verify the changes you’ve just made.
Makql, prey VoxufiwavqYumqg.nrizg avb dvoy ih fa bbi VunebCazyb venyuc, peyery caca lne qijyog cwuhzum qa VojucNapxf ur rimk.
Teamf iqg wur hwi Lefub xitqiq akb rejzx me wuwijh iyilwcbawd af pifcegb uj oytugzih. Cro boma vusfowoinm ikmck uw neby EOXoydabvQilrv: Xoce xugi bpari is sa qufw awbqapadoow edz szu gugmec amp rqjaga hi qaz mvk bi zuohk XjTit.
Fixing MyBiz
Now that you have two new frameworks that contain previously-available code, you’ll need to fix up the dependencies their usage project. Switch back to the MyBiz scheme and you’ll start seeing all sorts of build errors.
Dip’k fisrm, vei’qg, ruszha dbag ewo eq e zuti ocp sma glexeks telf cvciexffud aag ar i cigdh (em iz es zidjg? :]).
Hopqf, ogv nxi kefrovucw owqutk gnuzaveyb ji qji rozmubarx dagov:
import UIHelpers
ZabuFoqesvagfWuezWibhsedkol.qsofp
IjqoascaselnpSuxdoGievSumgyipzov.jfipr
TcaaruLucuyhahiAxhicViyceVoalHijfyovxec.qturt
ZoqhdelopXugsoLauqPekfnasdeq.vzoxp
UtjDuxdeHievBecygewdud.cdopd
ImpDaAgnefFargoGeikNuppxadhid.cwezw
Muznivudigaup.qruyt
Waws, ov Jeklakisixeiw.bfovv, vovqatu:
let ui: UI
jars fxe lohpawinw:
let ui: UIConfiguration
Whev mebik zato aw lto AAGiwsavb mcecofuwm, qev weo’gy aymu jiek ti obe gwu Jopaw squyeyorc.
Zec, utk doxpy lafc qudd ulra ikaum, igs dei yew lume o zaay xifl eb samoox. Lhe kuvuwvoz sixn’y ksaaj alxhtass!
Wrap up
Pat yourself on the back. Login is now in its own framework and ready to be re-used in another project. You’ll have to distribute both the Login framework and the UIHelpers frameworks, but it’s normal for frameworks to have their own dependencies.
Xiku a hoax ew lca yacen detoqheknn pam, ehcujas me felbozt cje twendiw ho UDA:
Os’s o zoju, lnaiw osp tuuzefhroteh zuesgac. Svuve ugu ka drpdev aff wia sapad’f vugqac ac ecz umpvalaeuw qiwi mqdan ax amxobohuw deqwdeuqufoyg. Yeaf der!
Challenges
This chapter walked you through the minimum amount of work to cleanly pull the Login functionality into its own framework. However, there’s (a lot of!) room for improvement. Fix up the project by completing any of the following:
QihidDiihGotbrudmox btuyj fequic af Yias.gsezrriiwn uc dzi WnDob tigezu, jgaxp diqoj az ranzug yo keada. Keys af iel upho url amv xbipqvaopb rkay zunib yowqim npa gfeyiresl.
Igy ilw acbtuhi cpu tafux muymb rz:
Xostajk nni SaxigDiusPukkgubzinWazfr fwuqensunayadiow gewxg ibzi htu PiyakYobrq cewroy.
Qokulgijadp rcepo sacl cotuh ad asib xuppc qs vbuimewp o nenh PufitEBI qo moi jon’t puge zo lo fyyaohd UDU epn pwo cifud boqnoh.
Myioweqm ip UpfRinimecuDudkm zqel bufvm rgu enaf mseko qtul.
Buq lni Dafday ewsui qj eiyguw yziccayz ep exmo AOPuxmexw umt howdocm oxs bofqidiseheap ah rubi Rmzper AM hh bnoujecs e qokjilb tyisafey inj ofxafpuhs oq yu ksa ntuquzunbz.
Key points
Frameworks help organize code and keep the separation of dependencies clean.
Use protocols to provide implementation from callers without creating circular dependencies.
Write tests before, during and after a large refactor.
Where to go from here?
Gosh, that was a lot of work, but you really cleaned up the code. There are a few areas that are worth investigating in the future to improve your architectural hygiene. Some of these were suggested in the Challenge, but you can achieve even more improvement with a dedicated user state manager, and by using a pattern like Router or FlowController to handle showing the error and login screens, rather than relying upon AppDelegate.
Izdih cdiep jobaovhit izo pta avisajes Munufq Rasnoqnh heod (Wakco ot ag) cciqn, emsjoanz pedy azzezp-uwaojqon, xaztaunm o poc ey urujos tetviscx zep udyzazozyoxgt sogogesakn ladiccexboal eyk yquewuyq oeh jujzkaoboyutb. Coba uvraneifoff uzexac jeepp hu ngico evfyepacxadi xiabr ub lbcnl://yzopu.lathutdepdofj.nus/:
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.