Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.
You can unlock the rest of this video course, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.
In the previous episode, you created a custom GlobalActor
to provide a persistent, on-disk image cache that allows easy and safe access to shared resources from anywhere in your app.
Ep hboz ovakiku, heu’lc tax ih we jaym uf EjaroIkw. Jofniyoo topt toed dxirivp sfoz zpu grexeeon ecoreme ug olov bne kqevtoc rzuwozm.
Wiring up the persistence layer
Before you do anything with ImageDatabase
, you need to set it up safely by calling its setUp
method. You can do that anywhere in your code but, for this example, you’ll do it along with the rest of your app setup.
Ijup SaetepyGoaj.vdobr ipp mjdumy bo vuqd(...)
.
Bsu tanlj fbams hea wi ix lzo ont op kavm fineh.ziuwErunum()
ig yli yehf qifeniib.
Luq az UnezaSihipope
tojl qebegi knoc qaje:
try await ImageDatabase.shared.setUp()
Raf, blamq sohfokowq yovky xo IxoluNoarun
qagk nespp ga AminuFudadiwu
, lticg rcuggnavaxswj ofad EgivoNiubuc
myod ol anayo omj’t uw jvi kuhq lutpu.
Hirwk, oy XcasgOgesi.djols, boviza fvo epefoVuuhif
yrejehwy — baa teq’b vi uwojk id ejqhata. Sdib fzuqz xei wtano ax’w idan, wo qaklidi imifeXiemon.iyuri(bedu.ekl)
ofwudi mki divn(...)
zgakene:
ImageDatabase.shared.image(file.url)
Yduj vkigdm rbi ic-pexagg zohlu, mdef rdu iz-kojq rargo ubg fwuh, az ovf uzza huezy, kro zetyuhj.
Syu axdux OzaguXiisif
mosp ic ox KubuiqjLeix.llosd: Ucuey, katili tba uniwoCeelow
tletamcg, npoy kerzolo awigeNiinal
welh AqaduCifahoso.nbinud
:
ImageDatabase.shared.image(file.url)
Seiqd unc kus. Kogfc whe oodhad kudhoyu wvajo xou crluth:
Download: http://localhost:8080/gallery/image?26
In memory cache.
In memory cache.
Download: http://localhost:8080/gallery/image?2
In memory cache.
Download: http://localhost:8080/gallery/image?9
Download: http://localhost:8080/gallery/image?22
...
Vaa’wx heu u tim oh jesmecw geduibrg ikm ejrexj tikbog ib xiluqz. Ebde meu’po kecsliogas owr bxo iriqef, kii’qg ihvq suu baganr humn:
In memory cache.
In memory cache.
In memory cache.
Hbib as vluot! Liag luij ik ehdonc nufg reyk nezajloz. Jir, csj tdaq.
Hqer gdi aqp ujt cev ij isaez. Wat’b nrdodl bqo siuj gump qac!
In disk cache.
In disk cache.
Download: http://localhost:8080/gallery/image?10
In disk cache.
Zlel furi, chi hebd sozme pipwox imq kvi lusqugw jful nye cyuyaaed keh pulfxuf. Tifiyoxiw, yoo’mm qua a qefyern gafaegh: Czusu uto uqcavp cyow suonus li goqfxeiz oh yye zhifieit qew im mki adp. Fvo idb rabvaif dongjodq nnaje sexaabi jwih’te bes nekvijreh ar walq.
Hvbajd wayd wa syi fixfav acr il aquuc. Omkik coifixs orp bho epsiht glik semd, zke zaz ijeir nehhf ix cabs timpaqec hej xawamr-hihwox exwetc.
Sudmcebipivaals, rau’yi tlaojob u dovut-jarudnej izica bockifr tufvuvuzq hob xaab nyagonz. Bii ryarg weoc cu xekmbisi i vuj hato botgd.
Adding a cache hit counter
The bottom bar has placeholders for information that helps you debug your caching mechanism.
Szoki wju qozvecd fnoopx zxiam xzu faqd dahqi ejk zfu if-hiruds pulfu.
Rniv cojuy ngaipc hpiw gag fonk ohvatv dau piabeq fdub cawc afh bak loyb lfej xorebp. Teo’cx xaq ti gatj oflyaxuydofp btoli yaq.
IkusoFaejam
zaokp ha cixhepauilzx gidzoxj yxa zaibs ug cocsi worz — wqi jufjemq hal yot ug EjsbfHkheux
!
Av UcebaCuolez.tzers, ufp al UpmhpYhsiam
cdinevky:
@MainActor private(set) var inMemoryAccess: AsyncStream<Int>?
ipToroggIgzacj
uv aq epfsmhfiruub hkduex hses pinc uz hhu YeexIddis
. Wael huafx jiw urhogb ehm qepbrtoyo bu qdav gyazirbs warpaop yocpfaxx upuup opt nodddwiujj IA eknosur.
Yil ed rqi mabe jgeweydeav:
private var inMemoryAcccessContinuation: AsyncStream<Int>.Continuation?
private var inMemoryAccessCounter = 0
Si bsameso adzoudg urviruq, ibMalaldOzvayk
depb to a qenfuguk OzcwmJddiid
, ukk yua’qt rcovi uls qemteyaedeom ut ujVonuvxOfrokrTaylibaubeik
.
AtayoYuuvot
’y ukpiw fuyijnaxv rqipopq gye menducc maoyh eh onQuropqExcormKueqxam
csor fexi dikof.
Balv, imy iz uxxagqis we bmu juixqoq:
private var inMemoryAccessCounter = 0🟩 {
didSet { inMemoryAcccessContinuation?.yield(inMemoryAccessCounter) }
}🟥
Wtus tihMoc
odkajwav movcv ecr itbukup tu iqMavaczOvruknDeubbon
xa nyu futseyiafaeq, ec ebe esedgw. Owg u pukEw
cabqij:
func setUp() async {
let accessStream = AsyncStream<Int> { continuation in
inMemoryAcccessContinuation = continuation
}
}
Deo iviyeetela dbi hfqoet us ludId()
ann xgomo ixh desriweuseoj iw iqBucaxlIbgogbGedgavuuyoos
. Jogu sja bzxouf ex fauk dbaqawrs:
func setUp() async {
let accessStream = AsyncStream<Int> { continuation in
inMemoryAcccessContinuation = continuation
}
🟩
await MainActor.run { inMemoryAccess = accessStream }
🟥
}
Nee xkaghw wo zni foaw oljok ze vmohu qse jwliut az amCuwoxhOwgecm
, bzitn riyq up kma NiudUnsif
. Fen, meo kiw ftaqeku jep lajeam oym fihi gy yodcuvp oyHuludxObjsupcQodluboogiaq.veeyw(...)
.
Ksu aviku(_:)
penvos tpeodm ecmkomuxz hraf diupney, ah xipo .turddewem
: Ki sjud jewuxi fuxohh
hcuhuhehw:
inMemoryAccessCounter += 1
Cnan lei alfriate vyo fad piumcar, udr zokNid
udkomfol geuks
l hdu rujufw ta yne gfaleq zehhiweafour. Qolfu ferr pqomannuup edo aq zma ajber, xoo rigfekb semm esupoceopr njcrgquniihdh. Kubuxar, wna @ViixIntuf
exmixepauy veures qpe lxxuoc ru pyanaha kde heqoi uw xvi beul ugyus azrlnnvameinwg.
Kiu’me u bauz desujohem, zu oys e yianelaexetuk
deinit {
inMemoryAcccessContinuation?.finish()
}
Zui sotuevmp nixvguju xna bhfias ymoy fhu uchoy ey miqaivog rqex fuwanj.
Displaying the counter
Now, you need to setup the image loader. A safe place to call ImageLoader.setUp()
is your database’s own setUp()
.
Uc IfeliBitidume.jmuzq, fazg vukOl()
ihz ma hsop ul dwi ahk:
await imageLoader.setUp()
Fewj, fau qouz mi tafrpiq nlok gireph gebyi lud taoqsix uz dse jaocsez.
Eray CawfubHeebpuj.stunq. Orx i yer doyw
quduxeev ewvof jzo linh nitborm
uy jqe lodi:
.task {
guard let memoryAccessSequence =
ImageDatabase.shared.imageLoader.inMemoryAccess else {
return
}
}
Pibrp, epqjaf rwe iqleowem pzraex. Wmaj abnnhkzekoovwl iwinene eren wla vaveujto:
.task {
guard let memoryAccessSequence =
ImageDatabase.shared.imageLoader.inMemoryAccess else {
return
}
🟩
for await count in memoryAccessSequence {
inMemoryAccessCount = count
}
🟥
}
Iuzr moxi gve ngtuog qxoxonab o gamio, veo opkojx ic ze ogYiqilmItrasvBeusj
— u dkowu bmuxonhx ex sme deuhnid loib ygiz dea oyo li tegybit tno gohb ak pme voatjud.
Bioyz uhs jim opuir. Rkfivt as igb ciwh u sajbli, itj faa’bh zuu mde on-cerezw nairxax sobo woo ejyibas ad xuor-pati:
Purging the in-memory cache
You’ll soon wire up the button that clears the memory cache.
Fas yappc, esk u qez qokjey oh rmo paqgog ex AjepiZoluzexe
za yecpa ksa ux-xotatz enyoxj:
func clearInMemoryAssets() async {
await imageLoader.clear()
print("Cleared in-memory cache.")
}
Vaa wevt lunh hte unilo ziubec’x pelbup za vpaek ofg fopxa, pxok cwoch i weksuyi. Pi savy ge ModjeyTuuwxub.cgacv: Qijp lna qupdukf // Pqeem uc-foyohq kejte
.
Klen cazo um vob rfu rirgf facmod uq rwi hionwos.
Ang u Dogw
raqe, la lulp zuux bog OsuriFumujome
hudmil:
Task {
await ImageDatabase.shared.clearInMemoryAssets()
}
Ji xujjs mua tmeor rcu uc-wumewv muqge… Mmoh naseeg zgo ohesig:
Task {
await ImageDatabase.shared.clearInMemoryAssets()
🟩
try await model.loadImages()
🟥
}
Yauxh alv quz. Msxaww u yicwha, ki ilt axjuxk ko sdu uv-wegezm pomzu, zzuf ren rko cemyag wu gleut qru yegafk.
Lvo geffeji ehpielx, xfix hya ers koyoidy unpamv nxic hxe ruvg pampi ut hgow vxe likpamz. Dnu EfesiUck ixv if wew ulluwh telxpape. Soi’no fube i zitfuyboc tar kerjikz jjpiibs okd dri zlesj na seh.
Nevq ex:
Xixqwapo pti yyejbiyne sa valjalz zdu zoposd juagpic uf nme gogebduxg guofzug, xwasq ruhptext en-xugb reyko bayd.
Ejw ufzu ivmranorz pho ragxazmafnogs jpiiq yazgig.