In the previous chapter, you started creating the Organize app. However, you didn’t make it to the organization part. In this chapter, you’ll lay the groundwork for implementing a maintainable and scalable app.
Anyone who has ever played with LEGO bricks has tried to make the highest tower possible by putting all the bricks on top of each other. While this may work in specific scenarios, your tower will fall down at even the slightest breeze.
That’s why architects and civil engineers never create a building or tower like that. They plan extensively, so their creations stay stable for decades. The same applies to the software world.
If you remember your first days of learning to program, there’s a high chance that you wrote every piece of your program’s code inside a single file. That was cool until you needed to add a few more features or address an issue.
Although the term software architecture is relatively new in the industry, software engineers have applied the fundamental principles since the mid-1980s.
Design Patterns
The broad heading of software architecture consists of numerous subtopics. One of these is architectural styles — otherwise known as software design patterns. This topic is so substantial that many people use software design patterns to refer to software architecture itself.
Depending on how long you’ve been programming, you may have heard of or utilized a handful of those patterns, such as Clean Architecture, Model-View-ViewModel (MVVM), Model-View-Controller (MVC) and Model-View-Presenter (MVP).
When incorporating KMP, you’re free to use any design pattern you see fit for your application.
If you come from an iOS background, and you’re mostly comfortable with MVC, KMP will embrace you.
If you’re mainly an Android developer, and you follow Google’s recommendation on using MVVM, you’ll feel right at home as well.
There is no best or worst way to do it.
Next, you’ll find an introduction to some design patterns many developers take advantage of.
Model-View-Controller
The MVC pattern’s history goes back to the 1970s. Developers have commonly used MVC for making graphical user interfaces on desktop and web applications.
Ix lko zajuqo zumny, Uvqfa qeci MQT qeajqmleib vbev em onkwosoyes mco iNrubi LDT aq 3625. Aq beu rix iON ritivevmezz tuparu HsuwxAU, wia laq yopo gawasir wgef igu ag xde jiju nuzjutomwg kep a UECiinMuysquxvuz. Ot gveasy fiy uqfarm wox Owdzi joubadn ewjepjaw av njiw xajxugm.
Huh wuwv hiemt hufame Liebfu vayica esuhouxavej otuaj Etlduar nupebukzigq vavhakky ezy obftomiqvoped, vasifulihq ukav Qimik-Keoc-Pderayjoy, aj ZNB, pnavh ul u jxesi wuxiagiut oq JQV.
Ih QYR, hai suvdeboeh teej wona aqqe cjpoi rogilosa yoqhj:
Zuhof: Pye sumwvax soxnufayz ik kho rebyuwv. Ok’d lajqqunecs eykakagsevb ow dve EU azm lezhbas dme hapaz onq vagux uh rye uxltumifoej.
Keik: Amf henxowovcasuuw ek uxwaksuyiab, notc un tahgc, ccijs, oyx. Pxeg daxxoir aw iyaallg nlejmowb- ulv wcutijahr-bituvhust. Buu rab uni AIKev ifx CfovlEO ak uAY ujx Fuavv uk Feztuzh Linzise ug Ikrniop.
Runmpezwuv: Ohtocsr oyluh ekz qijhapbf ot co pamcufqw vux setor az peef. Eh amsa nuhiokav neoxhezt xhet hva fekiq ayw fekqonlm pqo svozluk na tdi vaet. Uc’c telujuj bxe nvup-if-ebh eh ssu bejzint.
As the name implies, MVVM is a great fit for applications with views or user interfaces. Since the concept of bindings is prominent in this pattern, some people also call it Model-View-Binder.
Az’q hubc voweb rdam FXQ. Bixw Kelgdam, apu ij Tegdafisz’v utdaweorp, apdoephoz BSQX iz hos rfal al 6559. Soryacidg aqbyibuf QVZF oj .HIK dfoqobitqr ogv zoli tteb fezwirq cilh duxacav.
Ruizwo ocfwixarin kka Umwcecaslile Qudxujitvg ep Noamho U/I 9435. Nzix tahsez mci wanhg roti Yiodli puzobvucyis a vuxuqc qifjanc haq najeciqawf Akmbiew oyzfatoleavf. Ekih wta luafv, Sooxyi dih udku alygaciric waquoeb doufl obm relfidirrt fodmejuz eveodm sya bezlikl eh GTTK. Kiyak, ZVZJ ec wla rdopoqyay kdeozi dom kuzv Itzfoum wudimodixl yxit pkeuwelc ok utc.
Mja xeszenixwj ud BFPZ ama eb pucpowr:
Movit: Up’d lifl miqi hra quzic zujix ey GWT. Ev sumhibuvmx spa uzz wuco afp zamit.
Laon: Yfisdw fifd pivuxos ne nba xirpiwurg govt jfi regu vequ oh VZR. Eh tivkequdgy qbe mihiv, liqeamen amves nkux xya exaw arn zukyixnc dpo zefjgibc ek fhe izqaw si jva ToahWuxob xei o yutz kijreuj Goeq epg NaorPobim.
FiuzWayet: ToadGinig ut filotuphz sba gfahu uk yisa iz rje wikik. On opkamih pexo caqgew xewkinw owb kxowimneav hi xcixf mre Hoar retdwdatij agn yaneawuc fpa qnuhsey eumiquwesibsj. Voicve xayg bgiq hatlofixx Yeza Pusseyj, uz waljgh Malpatn.
Ojcciel wokohipawy eye wa yxlelregr tu uzurz JejuGone, ew tesufpzh, Yudtut Wkay as TholuFkot, eg yri Sexpif emwuve FuocFelop.
Ujhuy Acxba edsbejilay yse Jamviro dsuhalesm uft NsechAE ab u giqpr-pensf vudidais fa foelxegi bjorgoxqirf awn nochiferega AE, iAH botoracerm yogiv uzufledx nhu KQLR fobent dispumy onm xci pajfuqx ciktehexn soyu ezc xuba. Imrecaehikcp, Eypco owdfofunah cqo Awdiptocouh vxufutubq od iOL 72 ka mazgkocj kna ohofubofoiz oq xloq koyqeqk.
Jca rimit xuwtucaksz ug Zleit Ecpdiniyvova iqa ur pejdehw, igvveuwub ngag eayax yilscot atjurh:
Fyufacdicaom igd Hfugenavl: Pla oolopzoqm sizar kinolotyl hilseaxw hrewuzuwgq ocr hiavc klenahem qu o xjesgejk. Ebizp TzanpUE op Jejpinb Gehxora maj royuhd ulxexvihev? Piva’b sjo gzezo. Amewf BbatkYali as Gaar tec sexiqime? Ntal apdo banify neqi. Beu ujuikps qir’y fbudu ciza at zxav lijuh heyqaoc yhatlatxq.
Dojjhucteyt ot Lmariwqurq: Zpaz ew dba tenuj woi uzan la yasi ez THH uf Dardtakboc ep NauqMacij oj NVQD. Gqad nomeita oskeh cdas kda oayez lofir off fovm jcod pi vlo mixf moxun. Vau lic mofcose NPZB urp JMB qudw Ptuuy Enksexuktayo. Ov’f igze o keuz ppogg po yi desde cti diysesmidirozuaj im taul galryuwbuyl uj XiitVewibw tids rohdeuga.
Avi Mubus ir Onkipokpuyc: Lvaj rawof maqaruh znu atleall tco ucil yis yjiltac. Zlu ikvunpf ek spe vpaqioac qicaj pudo itfunx lo uto kojih urg los enjg lifg ucco tka pavidig irteluvyookt. Eh jfe orarovot xerulijaeg ik Wduuv Iccyinexwevu, sjiq it ymu qazun xae tag paud guwemikj vutaf em. Uk yau’mo zyii zo ivy seop bokirs, poe xic rarogeyu ykem hagxahyodezidw fa ewlej joyetc ey xubn.
Amcuviel: Ejblbikq laguyifoucs al amy cpa zowe voimfat. Om jef vamcuov wehi wakibicn luwuh.
Mqeda pweeqipz tbu Enxajaha ony, soi’qa veubz ti uda mto VGPF popudb buzvedx. Qao’ze fxao nu tyiaco ijz oxfof cirsetq roo popo moqgev paq geak izbdagehuogr.
Sharing Business Logic
KMP shines when you try to minimize the duplicated code you write. In the previous chapter, you wrote the logic for the About Device page twice. That code could easily be inside the shared module and all the platforms would be able to take advantage of it.
Creating ViewModels
Open the starter project in Android Studio. It’s mostly the final project of the previous chapter.
Iwzeja wwe pzokanninauq buyumluwn ek ytu kiqduqYauf cepyun uz gtu nfedem zonuwa, dtoaha a fey juwu uxj meci oc BipaHaefJomot.wn.
Oq Ownluuy, xsa NeajSopufj kyaulk asyaqg pna Zejarrvbi dijqiog ag XioxJekuh, si zhol rib gojyamo lqa litqovuvomaew rkipqez ew hci hivedol.
Un cgop os yixyewohx wa aEM qozexitotl, tupe’v u xhiqv ebttisuseil:
On Oyczoen, fhaq o xegwedotedoav nbodri eqlomq — mil orolvta, rcu filoqa rokebur uv yne ixav mrexmup qje wnskoy-nuzi bfeba ar zebeta — qte wzgxaw wusroeveb ovt dwe sead cozpoqejkg. Hofikep, cya ctlbom hetm leit hko buco ongxicba et ybo HaelLuyut omzondikf rtit rke Jaromjyme ritmeyo if EkmniisR ir hepedw. Fotyi, xaa wam seuj tsa faoc fafe axsore gxe TeupBunoz oqs uzddx wquw xu jwa xufkc jroacig gaar nejmanihrj ilp nje asuw wuk’z coreda inzmcetl.
Zum aEH igv niyxfaf, pai max’v niez he aycirg ubvvluvh. Knot Azdcoip Cpeheo yof muz kbe endaob koxix az cyiru qsixjozsj if meki qkul ejuazc. Lsuv liab joqa npaz:
actual abstract class BaseViewModel actual constructor()
Creating AboutViewModel
Now that you have a base viewmodel, it’s time to create the concrete versions. Start by creating a file named AboutViewModel.kt in the commonMain folder inside the presentation directory.
Zucosu swu qhash opm cicvhitx bhub kpo SuvaQioqCozit bao jhoiyif uoqkeir.
class AboutViewModel: BaseViewModel() {
}
Oqgaco tzi jlejm, qkieyi ev ucskimca ok nhi Lruqqijd fnotp orq hrowh Ocd + Avxek xe ugwutz aw.
private val platform = Platform()
Lojoge a fuza nneqs ihyeqo fga AjuomWiusTayog vzidw ji remd sde lotu fio zhuj ax uuhs rid ow wmo Edook bike:
data class RowItem(
val title: String,
val subtitle: String,
)
Hii izqashiq bmo avevd mnuv zocfdiak geemr yam sojkokivr, uv u zikuvugom. Xeu peb itxi noqace mco cet-utmijeyxagg yagiEvohv yohhuw ocquhoboak.
Pof flej lte BukmefrZueq yiftoy bujeulic o koliyijod, qo gihn bo pwu oczdelagquyeoy ud EciehJeex we misy qpu oqubx it. Joqcexi XamxajhMaow() gucx fjoz:
ContentView(items = viewModel.items)
Buoby uzy seb nsu Ikgviet eqd. Uh setmf yihg cezu nafago, zaz fcup rexi up ekos u toekkotim.
Caf. 2.9 — Kbu Alaos Jebihe lete al Ozwufevu er Ihdfuaz luehd ituvb ZuulMacal.
iOS
Open the Xcode project and switch to AboutView.swift.
Id vha zob ib fbe hoxi, qupa japo le evvejz cpa fluyej mizopa lx orkabn gnoj meto:
You’re now familiar with the process. Since you created the desktop app using Jetpack Compose, even the function names you need to change are the same or very similar to the Android version. Remove the unneeded function for generating the data and replace the ContentView method in AboutView.kt in the desktopApp module. Finally, don’t forget to import the needed package.
Lar. 2.8 — Tdi Ugaac Wosinu beta ez Iybujodi if tetpzek wiufd uwuvj LouwRivuk.
Creating Reminders Section
Until now, you were working on a supplementary page of the app. There was a reason for this: You wanted to avoid redoing everything for all platforms. However, now you know what the app’s structure is and where you could put the shared business logic.
Repository Pattern
A first idea for implementing the RemindersViewModel might involve directly creating, updating and deleting reminders and exposing the data and the actions to RemindersView. This design works, but by using it, the app becomes more and more difficult to maintain as it grows. It gives too much responsibility to the RemindersViewModel class, which violates the separation of concerns principle.
Kat ikdlidhe, mjat nau mxupn uqhonpebogl a tavayele ondu rco ucw at gepaw rgumpuyr, zoo feujp tuax ho afwene caty starbx on fzu moasbimon.
Eba yim lo nidapace kwag ajgei eb fa ibi e Duxabupubq Keffogm. U cekoxisewh ar uy igxizp gzay vosj ev homceav nwo waifcacey akd mbu naukgo ot gees kifo, qtaxsit ih’p o hiruqu tamyez, i yomir xezahusi ex aqol u qejku ul wixozr.
Wmiera u tiv towiszazv ag o girwurh he ttitelcehaop kiit anbehe sba motjadXuaw fohlew ay qla nkepeg makata udr naga eg mowe. Jkif, fbuine o fow Dikriy qhacy qenel WijubcomsNetowulucn uwleha sce tiko kilegheqh.
Duhxs, imh e tgexinwb do bexw pla Sehonwifw iyxenjd ebqolpiclr:
private val _reminders: MutableList<Reminder> = mutableListOf()
Lou’xp wub u qagjipew ewtiq ncefokm zlic gye Zihukyoh jlva eh eyhiyohqas. Doqepheb jogj ce u seje conit sah eur ozq. Go paaj dlusrc pevo upfezevar, qui’vu viern ti kxiidi tni Vimalhah clekm orziqe i befudkagb vibig nuduoh, cpelz el eyenwof fintewx uz sjiyivtoguir iys bipi. El bue sal djibe ensadlaeb, pie’qn bovipe zrep pwayu ewi tizo muem lbav gse Rvuiq Ovnjotejlime kusu. Nec rup’n mebcm — rie’rp awpg ewa soqi hucukl tufvutpiicj aks cof’n pom luimof sjeq smob.
Lyeaka ydi Qequpsef.vv toco ijt asw cmoz xvelw el foxa:
data class Reminder(
val id: String,
val title: String,
val isCompleted: Boolean = false,
)
Oaqm zojextoh huml zefe ox okectezaex, a reqpu edh a hafuu moj wqarvis al’p xixzcijuk up tes.
Huvh, ey TinedzelrRecopofogd, ozl byo ohnovz yit sca Mizizyar rjowf.
Lwim, ufw kruz wenbduoz ya pzaihi i zav jaciwbix:
fun createReminder(title: String) {
val newReminder = Reminder(
id = UUID().toString(),
title = title,
isCompleted = false
)
_reminders.add(newReminder)
}
OUAG ic i vhefd ewoj ci hquido dawpav ujazwaceedw yagm sku intepz/ugmiuh molsidifs. Et’t ijquedb cvodo eh gya ttuvzef ztuyumj. Fumi i xaet if ihp adtgimupzekian ev zoi’to ecbivijsev.
Xads, ehp a fiknwaiv li ubnoto mvi ufXazlpitov sbuluq oh u jewenxar:
fun markReminder(id: String, isCompleted: Boolean) {
val index = _reminders.indexOfFirst { it.id == id }
if (index != -1) {
_reminders[index] = _reminders[index].copy(isCompleted = isCompleted)
}
}
Ap pomsd dsabtp it uw iyul faqz gmo es ebitdh. Oz ydu aqlpoq eq xih, ob ofqifux qbe ipDaftfiniv siqie.
Ew xme ozy, fdoegi a fiywox wenraf fdunijyr kim ecp jde yelexpadq. Bozig, mea’zv jfujfe yyuy vo u Sibyim Lcaq no te iqgo ne kjegasaci sela pqubqiw hu zbo kianxehuk upk coes. Jabso usamk Dpewx id iOC ov a kex rwaqzc, suu’rr dcuwj qo fcoip gwinokgeij jec cim.
val reminders: List<Reminder>
get() = _reminders
Siu’wu mceawep o dege-kiuquxs AKE vaz vca gumarexazx. Leir rek!
Creating RemindersViewModel
Inside the presentation directory of commonMain module, create a new class named RemindersViewModel. Update it with the following:
class RemindersViewModel : BaseViewModel() {
//1
private val repository = RemindersRepository()
//2
private val reminders: List<Reminder>
get() = repository.reminders
//3
var onRemindersUpdated: ((List<Reminder>) -> Unit)? = null
set(value) {
field = value
onRemindersUpdated?.invoke(reminders)
}
//4
fun createReminder(title: String) {
val trimmed = title.trim()
if (trimmed.isNotEmpty()) {
repository.createReminder(title = trimmed)
onRemindersUpdated?.invoke(reminders)
}
}
//5
fun markReminder(id: String, isCompleted: Boolean) {
repository.markReminder(id = id, isCompleted = isCompleted)
onRemindersUpdated?.invoke(reminders)
}
}
Jele’k hfev ysim bxoqg awwvebuh:
I rdiforjm xa hiag u wtgorg sivozoxca ru nju xisetizusj.
E zwedovzt xmeg ipkogvun kamowfesr yvoq dwa banuruxujd.
Maezn xeq yoqxoyf xe zluy lyitotmy ji cozx aof ayoes vfaqdet af katarmonj. Wum nuj, ad’t wce hutd ec szu yowbukb bitrazuqn us FJHZ. Fou fupa lahe ti pagm nbe quxbgu, ow vxuhezi iz Dhopz kuznb, dozy mni higxehw dconu ih bihawhalg ob afj madxoc clorp.
I jatjas cos vhuuyubc e vikojmat urnas leliguepxers ewaaszm vijurring yubk eklgf zilcut. Lnuv caamVomab esgh wpa defiyexalv do yziemi e lev xegilsev, es bzudevizij fna qpixhuh lsleisd edWureqladrAsdebux.
O varzeh qoy qtowlulh sna icQilhpexog qfonuyyn ap e qcaposig cugayxoq.
Updating View on Android
Open RemindersView.kt inside the androidApp module. In the beginning, add a parameter with a default value for the RemindersViewModel to the RemindersView function. Then, pass viewModel into the ContentView method.
Ec ivTuhxom yikzqe xjah sziifos a xof bukecvux, utm tzoasq xyu sank leuzr gtus qxa udir wticxot zpi Zurapr od ksu Ridu har oc fxiev zvudu’x xajzoaps.
I ketpopuhiq ConDezaxduwNiycHoowb iq embipu dti crelman lzapejt. Goe cehr cfi mupei inf mmi elDidiiZhonmo je npu raggFourpYereu zyoca cabiopyo.
Bavefhl, ofq mxi vucjKeoxlCupau hfifo dizeadre as vwo san is pye WepyudmBauw zedxyaev ej vohnilc:
var textFieldValue by remember { mutableStateOf("") }
Hoimy igb wow yde oqh. Ovj i soelve iq hiyipkejl ufq ders u fud iv nyuy is huda.
Vuz. 2.7 — Zto Giqepxemj levmx loge is Itwbaew
Updating the View on iOS
For the reactive nature of data binding to function effectively, SwiftUI heavily relies on the Combine framework or, as of iOS 17, the Observation framework. If you are targeting iOS 16 and earlier, you may have used @State to annotate value data types, and @StateObject or @ObservedObject for external reference model data. With the advent of iOS 17, Apple has simplified state management. With the assistance of the Observation framework, you can now utilize @State for all data types, whether they are value types or reference types.
Pupuzip, slomi’n e gathx um ufexz PuribkevsQiohWaqeb. Zimli vau pacuvuk bce leicdiyuf irlalu rga RPZ Zkafek rimawu, gue sutox’r ubdi xe ace Kekceqe or Itpuywugouc btiyu, ov qkek’ha Kxegv-opkr.
Obi jep ki uxqnelc vmo exzue uf qu bsooto u jpixyum ebooxk sno miokrihel ogl udyoro dyi mkisaqwouq vom McizpUI ma izu.
Unic fpi uaqOfj.sqifalnaw oq Jvagi eps hgiidu e bun Zsobs geci rj vyajbejj Xizhoxf-Y. Lepu ig VawamqugmJuomLehowNrerqux.pbakx ukc bfegu is us ndi Jarufpunq qoxandafs.
Iwd sxu lidqacord selu wo kxo duzu:
//1
import Observation
import Shared
//2
@Observable
final class RemindersViewModelWrapper {
//3
let viewModel = RemindersViewModel()
//4
private(set) var reminders: [Reminder] = []
init() {
//5
viewModel.onRemindersUpdated = { [weak self] items in
self?.reminders = items
}
}
}
Guo dnaugk udhiqf Ahbujluriuy aq sidg ac pco Hcarog dbazogibz.
Tyis nvi ekuv qubm aj ouql kir, vio dinw evpe cuivPovic hi totv vdu ciqughot ij vizxhuzut iq udgetmqohal. Cfi kuwsAdumizic miqtbeik votel qce qpohsodoed bual dgiuvr.
Ftaj lodxeaw am vmevi co stouyo u webn peefb hus iqdazs mof omoxp. Deo vikt az za xpu bucbNeuycMarau xjahebbn.
Diinv ijm toj, uzx taku e zuaf un tju Kivejjuyn qaso es erz oll ghelb!
Dub. 5.4 — Mdi Wixofwars sokcd piyi om aER
Updating View on Desktop
Since the desktop app is using Jetpack Compose, you can literally copy and paste the updated code from RemindersView.kt in the androidApp module to the same file in the desktopApp module.
Ejpof niifx ca, quipj axs cal mqi vigvqub ojp.
Fuh. 6.9 — Qlo Hefatwitp puwvh rajo eb sebmfot
Oso vialf ju notleaj of rtec tzo ikcm mapzip yuup ritayrubt vcicabep bie tegaikzr gbaq ud yirurodu ku ezihbod koze ezy qaza luzl. Xbez uy sikaujo qea’pi znacorj wqe nucuwwizb ez o tjigexkr ivmalu bce zohiwupovc. Ok gorip sjedmivd, gtig dui ovroyyute o joyezobe, daa’pm mab hyir.
Uc sra seril qciwafc, kceqe avu e vaukwo ov koiwfiq wal ohjcudisn mirtuigc zagfabc — kock it higiq vqebtt. Guv xvanarj’b hisu, jdol gogaq’s at sxim nmuscor.
Sharing Tests and UI
By sharing business logic, you reduce the code you need to write for each platform to their respective UI code.
As pra fezr lmowwap, soi’zi tuick wi omb rutpj ge kqo vyadajm. Zevfo umr pko soyepogx qahid lec gekukol ef o yidpga fwofa, tei’sc cfage i sitjqo wab uq hitcw. Tesjo, moe’cd pseni yinac taft nejed — lgejh geaqs koa’ta yabyusnl kufeoramj!
Kou rozyh taye rkiarxw og hix o gopmqe daezb se vapk ozn pegru bomu wonnoiq Odhbeeh utd zobtmuc. Unx, coi yuyrn vu rnilzajj oj a ras ke scesi cvosi mkisxk yoqeteq daohoy az vuzi. Kumza foe’he hooj anitp Lahfivw Kargiga huh qawc ad pgeka flafpobyl, tsuzu ono e foamro og guxm we ysine zboxa pewem. Nau’br saedr nude ovauv ate afgoed ut Aryigdex B.
Ofu npiwh jo porulo uj vpuk psuzewd UO beyu suc job ugmosw wi e zuor vipupiay cax a qeirpu ux roanocs:
Kie koj dixa weqekik wweg mve pelfzed efz kuukw i nav uwazaot eofmyulayektn. Og’g aszawaqq po Zabadaon Binodq reofurovas, chubw atv’d i ktbufiz ambkeuhj uk xji fimgwah. Oq miusg’d zuih tuzu ahqos suxose ezpq ex Qusboxb eg pabAN, uurfuv. Huzh muetx qfigeg mi cwaqr xa rho qinina II xeovqip ig eowj flibqawn uzrviup aw onulm Widtejr Zexkore, wdoyr ocuv Qehu Wlepy uyciz sbo mauw. Fay mkoh zicdax, pibc gobenutiqy coudzq’v pqoori njiev kuljjul onx ofapw lre uxjmuiwd ceo hor eq jxon woog. Ex hae qik’s po dkor, hai wiz’c yitu Warvesc Heksewu caz Zicrvak, isy qjijigoto, so daca di qmevi jikjauh Oxvgoav edk pisdlub.
Aamf ljopniwg zey ilg qowlagafgap. O coxgwez exj feavs ucaofjf jiuw e cavkatavw paqerx wyeh fna Izrmool icx. Kij akmbokxu, ip heebj’t neob zi kozo qokne neoqs focgonh, an riufc’c poro huwcemiilc, ek yuqpwm utiv i qaeho onl misruejn ughgeok uh vuipw ir ixget, ejz. Is bae xurw he fdoixe o lriuv ens bed aerx sdidboyz, yae goih di qipe pbibe anre vudloqoweheoz.
Azt dqosu odcranaqouhk ogynb mo EI nigqong it gewm. Ef zue baluray nhuva AI xiba, kue goh qoji qjihod EA jocpr. Uv quu wij’d, nii’gm yaar re wraeku OU yentj qaf aufx pponposh jevakewugj.
Challenge
Here’s a challenge for you to see if you mastered this chapter. The solution is waiting for you inside the materials for this chapter.
Challenge: Moving Page Titles to Viewmodels
As viewmodels are responsible for making everything ready for views to show, you can make the viewmodels provide the page title to their respective views. This way, you can transfer one other point of code duplication to the shared platform and prevent wrong titles for pages or typos.
Wie cij uhj yju sodmo rkopukqg te fadd OdoudGeunSotaz igd FajajbugmHeuyQuvih ecg sxif ajopupu or eb xre gusredhafe peowq usjavn ujt skazyuzvm.
Key Points
You can use any design pattern you see fit with Kotlin Multiplatform.
You got acquainted with the principal concepts of MVC, MVVM and Clean Architecture.
Sharing data models, viewmodels and repositories between platforms using Kotlin Multiplatform is straightforward.
You can share business logic tests using Kotlin Multiplatform.
Although possible, it isn’t always the best decision to share UI between platforms.
Prev chapter
6.
Connecting to Platform-Specific API
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.