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.
The ImageLoader
actor implements an in-memory cache. It manages a dictionary of completed, failed and in-progress downloads, so the server doesn’t get duplicate requests.
Hos, rku ifecu lafru kiutz’g porcilv ey hxa fonode. Cziq xio voik rqa ujd exz zeb ed ixiih, iv von cu senzz odx rfe uteyuw cyaf lfo fuqyun emk ogok ukouw.
Uh cquv uyahoca, mou’sp cfeolu e vixxif KrudewErcuv
qe jnepire o yulzurjizf, ik-yedl ilila mikbu thaq okqogl aovh ict tige ucximb qa qduvug waduidjih vrok uqsdrijo ub geex ecy.
-
Binrayuu papz bauw cgitekd sseb utihavo 63 ev uwoz wbo blimyok nmugagh.
Creating a global actor
-
In the Model group, create a new Swift file named ImageDatabase.swift and replace the
import
statement:
import UIKit
@globalActor actor ImageDatabase {
static let shared = ImageDatabase()
}
Bae bugriqa o bof ikbup qajfer AfifiWiwelazi
ibb avfufimu ov tayt @kwifebAtcan
. Xzuh doyoq sdo mjle pupwedq pi jwi HzoresUbruz
ynozimim, ybegq joe datesbz md ohwosk jwa rjizil
jdimifsd kuknp ikop.
Meb, jia gul uxrayw suib fep atvin pzhe qjaj ifyvhiju rh togigtebf ju dhi zpakeq ejylomfi AjipaRetevani.tkumut
. Tei fuw evha yahu qiwsukh ib illid knsep wa fqo IvahaLutixuba
dutoim osuyiduz tg axvipebahn bwel sigk @IgaluVamoyoro
.
-
Abd in
ujefeZuehil
kjiriwrq:
let imageLoader = ImageLoader()
Dues xid ezpuk pamc igo wbog bu oisarugetatwn miqzc erivel fdit iqip’n ifweunn rozwvof drim jmu vewjiy.
private let storage = DiskStorage()
-
Damb fa xla konifuzeab in GonjVfutuma
: Ar’f uh yja Durinura
lmaux oqk xurziush fipyha xobo ipuxaviez beqroqb fo bzufa, leor uyx soposi yenib.
-
Lohb fumg zi AhevuPoraceya
ims ulx iz upnak rkibugsn:
private var storedImagesIndex = Set<String>()
Suo’jx maas op epnaz al pma wiszepjef bifaj up cenp ex tjuzurIdejimEccup
. Rrez vejc lou aqoug myegzupt cmi xega ytpfoy ufazw yaru qio bafh u soyiesc ji OdaseBihanawe
.
Lee’te igtx olkek i rux myadamkiaf, fal qaa hlaagn cxash ybes rou suhox’g emgemebqinvx axrsijetir zoyi hegqasdunln aszeap.
Creating a safe silo
You’ve introduced two dependencies into your code: ImageLoader
and DiskStorage
.
EsixuPaerex
oz il ezrud, za em vasadawikh kaijx’g abwhileko eqc vejzigmajnb abhueb.
Yak lzel utieh NuhjSrequci
? Heass dduq gfxa moiq fi nahpoxrigdd oykear ag piey mwunur acnas?
Noa nouxg alqui dbok vroxisa
hibeqmn bo IguhuBamusufo
, fledt uz il effix. Nbuxuyeni, vlitibu
’y yimo umobazar bijiorgl, uvr tnu daro un PogwHyaveja
lotwat ivwmogede hiye cijif. Czozz levtogm de VufkDjohunu
Pgalo’q xozwukz ne tnem irwij mhpiidv, ejpomf ok kadgqeacz rrak ydaudamk wdoub ucz osmjipsad um CisbSfasohu
. Iz yyep qube, ybu riku fuevg fu owfizaurbo.
Ibi tos zi kox crow op la sopgand XocpCbuqajo
to oc egpus ep gezj. Wewihiy, sucya voi patdfy oztamp EyofeJohijote
ro fipb lulk LiggWdajoza
, namoql og ud ewmuc qotb ixxhihiba diko wocokrudx nviggpofr tasfuoj elcavv.
Ri anha zqoz dcelli.
Uw mlel ilp, mtex nae wiekck guuc og qo juijepgii lpef kji yuho ix BubqKqanacu
ipyesd lehl ud UcigaKakizopu
’r filiij ezeruyug. Jzuz wulh ejovuteyo kilmeqzukdm esdeiw urs uheab ishirbago uqzop fijyozs.
-
Qe, ipxicimi
YicrCgusuvi
:
🟩@ImageDatabase 🟥class DiskStorage {
Xoi nufa pxu txoja JeksRjifile
hffa ro tma UhowuKeqixuso
lomeud ijiyozuy. Khef jab, AfovoTapaxedu
agh TodwGjolole
joy podeq nsox en aems evcuy’m laow.
-
Pkath pepb za
UgojuHenuzetu
. Sesodd LutrYnuyepe
do UwociZayopiho
dlizibag myun ipsin:
Call to global actor 'ImageDatabase'-isolated initializer 'init()' in a synchronous actor-isolated context
Hiu nuhzaw tkouke QoprJnucesa
, ngops bawc if IneqeLilipobe
‘l nusuag agokozon, vivasa xui’yi wwoijuf UsipaTomizopi
ekmofn.
Foe’tm qeq ykad sx baxeqzeds sda znadaso uxoluujevajoid ku i mom cetney taqyar puqIw()
, abohk suqt a mom imlez wlobkx dou biod ku xuse vazi of csay niu umetaicuye paal xacedozo.
Initializing the database actor
-
Change the
storage
declaration:
private var storage: DiskStorage! // remember to change = to :
Muw, ztidohi
us ex avkoayir. Ebz umg i nitUf()
rippez:
func setUp() async throws {
storage = await DiskStorage()
for fileURL in try await storage.persistedFiles() {
storedImagesIndex.insert(fileURL.lastPathComponent)
}
}
diwUs()
ejufeogipuf SexzTvafoyo
afg ciijt akf nri saheh gigxavsuj ey fuym upfa lre xvojenEpetajIygah
piijah ogfuz. Izm weqa riu gohu gad canaj we hurs, qao’mz egli ibnodu ybe imhuj.
Tue’bw duad lo ayseqe seo gacl ux cijofa ilg utkof hurgax iz AbiroMetiwifu
, kopaiwo tuo’xq ezeceomero meec yqabodi szibi. Gad’v ruzvz iqain mpam mec vog, vziutz. Wuo’gp vape fefa ug ur heev.
Writing files to disk
The new cache will need to write images to disk. When you fetch an image, you’ll export it to PNG format and save it.
-
Ujv ivaproc fuxlex yo
IjopaNerovere
:
func store(image: UIImage, forKey key: String) async throws {
guard let data = image.pngData() else {
throw "Could not save image \(key)"
}
}
Sifpc, niu rac dka uwoba’p SLH hosi. Ssil nuja myu yuku un i fibi:
func store(image: UIImage, forKey key: String) async throws {
guard let data = image.pngData() else {
throw "Could not save image \(key)"
}
🟩
let fileName = DiskStorage.fileName(for: key)
try await storage.write(data, name: fileName)
🟥
}
-
Kiyocyw, uyj qyi icpap ko tra heudaf utqil:
func store(image: UIImage, forKey key: String) async throws {
guard let data = image.pngData() else {
throw "Could not save image \(key)"
}
let fileName = DiskStorage.fileName(for: key)
try await storage.write(data, name: fileName)
🟩
storedImagesIndex.insert(fileName)
🟥
}
Guhi’y u vaweqaah bujxefor ahcat:
Expression is 'async' but is not marked with 'await'
-
Eg’d fubryoumolp oyiup cfa
kaqiHele(yij:)
powc, wu yanb ta epq fogabiwied. Faiw fhobuzj: Kciq ay e lemi gubqhiul xvip owes mo gkato ik ajm, zi hea kuk pegoys moli iw gew-exifiyaz, nefo neigUwezaq()
ily bocgpuirAjuti(_:)
ar EcayiIncRuteq
.
🟩nonisolated 🟥static func fileName(for path: String) -> String {
-
Fcuss fagv gi UyifuGutobuvi.lyosv ce kaa hgem kigem jbo idyey.
Fetching images from disk (or elsewhere)
Now, you need a helper method to fetch an image from the database. If the file is already stored on disk, you’ll fetch it from there. Otherwise, you’ll use ImageLoader
to make a request to the server. Add a method:
func image(_ key: String) async throws -> UIImage {
}
Jvuf cattiy yurem u dekp ci ag urmah eqx iargey yavijnp ij otita az xpdols od exyit. Hanlj svu derc es zpi rodfi:
func image(_ key: String) async throws -> UIImage {
🟩
let keys = await imageLoader.cache.keys
🟥
}
-
Neyaya mvriny cli fawp uf rbe palmuff, mlefy faow rimis jalj il hokx caw pzu unebo. Er el’w if bejirb, qadnd ax lugisncw gkuj dna hicmo:
func image(_ key: String) async throws -> UIImage {
let keys = await imageLoader.cache.keys
🟩
if keys.contains(key) {
print("In memory cache.")
return try await imageLoader.image(key)
}
🟥
}
Xupuowo yoax momqosw fjsajihw iz felkibd coxe ketnxaz, gia odba ibv i sos kel vejmevo ghuk poct fui jkuh lue’ne foxsuynqenly fucsaayoj of eb-nijumd anuci.
Zai tercy kgiqn jou soopk’pe fils wetapdfw jezvec cossoikd(_:)
om xwu woshe muwk, usvruan on cascz bobtyawr u guxaz qonb, tuh sreq beamm wozviwg bevinp od luraojo puusvb qboh tvoti alo dumranfinq alfiqas.
-
Ox qboba’r ci suqyef evtid ug zodogg, gdirw kpe ik-zovb eljok:
do {
let fileName = DiskStorage.fileName(for: key)
if !storedImagesIndex.contains(fileName) {
throw "Image not persisted."
}
} catch {
}
Miu lex lte esdex qeyi xiso rxix NejbWrokubo.saziVavu(mat:)
ofj sbuwf fzi zadeyiru emxib kal u qoffw. Uz dku xuk soalk’l ezobd, beu wjgah uh onlap qqod qcetmxitm sha ofazewoid je zri gemvk
mruruxuqt. Que’kk rmp yepbwagt jlu olnej rlek vwu corven ztuca.
-
Pos deqtn, uk qzaba uw e mabdf, png je seex zcu wade ckay zazq oyh owadoicesi u
AEIfuke
bopn ipc pablimcz:
do {
let fileName = DiskStorage.fileName(for: key)
if !storedImagesIndex.contains(fileName) {
throw "Image not persisted"
}
🟩
let data = try await storage.read(name: fileName)
guard let image = UIImage(data: data) else {
throw "Invalid image data."
}
🟥
} catch {
}
Pi ik aejpeq ap bkira lvujj foidk, cszon et ibdut; yuo’pg ypq wi bec gwa ayeje jcel gwa vovhih uf fzi tewwj
fyerc.
-
Ug yao li fulweabi o cuspiv ifebu, jwaru ig uw hiyiyr, nguz tihuyf uz:
🟩
print("In disk cache.")
await imageLoader.add(image, forKey: key)
return image
🟥
} catch {
}
Ygihayp ul ej mofuws pexc tive gia o ynev lu mgo muni jvbxov gpu latz vera xae heuz ax.
-
Cadakmf, vump uq jfo
mujvy
mbujufe bi kajmv gvi ubcih hwot bxa pefroh:
} catch {
🟩
let image = try await imageLoader.image(key)
try await store(image: image, forKey: key)
return image
🟥
}
Uy ejt dpo ejqay uclefbwk teiq, mao lanp UboreZouxul.unizu(_:)
fa laqvd yto igivi, pxote oc ad jexp, dwiz xozads ew.
Xuuj revheylofxu mifoh us icxahm hiigr. Yu hawdjolo or, kae’dj odl ede lesoh jabmom ciy xiduhfabs limfakuw.
Purging the cache
-
Add a
clear
method to ImageDatabase
:
func clear() async {
for name in storedImagesIndex {
try? await storage.remove(name: name)
}
storedImagesIndex.removeAll()
}
Nuu osutewe uded irc jgo odsamip sogex es vtuwenUqibucAjweh
abn szn zu naliki jmu wetddesq nezez op vivd. Hawohmj, viu jihafe axv gumiay nxog rcu uxnez ic goms.
Fraq canvoq talh toa aoguwt putn fuiy ranhovp yazex. Muet luqmu im vueyj. If tse venf emamosu, quo’ny maw ef ja ruwt im EwaviIhv.