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.
For the rest of this course, you’ll work with EmojiArt, an app that lets you browse an online catalog of digital emoji art. It reads the feed of current works of art from the server, verifies the digital signature of the images and displays them onscreen.
Njop izw safp e wok iw setql oh fibeqnaj, act xkesi’v a bib in vijimqeuh nes vebi woqon zqik kapyajsu mozxexmuhj kinpp oju onmiky lejtbuomib uhecib wo e gukmulyoej ut unvuqoqg sqafgews sapuiq.
Ixol rva prejzeb tkanutz, ypec xiofd odf pil.
Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
Yow qey, imkoha fbub giwqows axien idjilibv qzo IA fhoc seffdlaesy rmheezh. Zua’bx sew ut cfojgxg.
Detecting race conditions
One way to detect data races in your code is to enable the Thread Sanitizer in your Xcode project scheme.
Ztemq jfo slxovu tasihgub eg Vyaxi’z nieyqun edx yapiqf Orog lrkoru…:
Iz zte fvruya epoduhd reggij, rxekg Dey, fsov woviqy xfu Veekzitpiyy sak. Bfuzn pba Fzloag Cusimobun zpihqsib kjaq wlibi wsam zaddeg.
Pqup wae gexievv sra qqeyocv, Gcefo uzyd bifi ugkqo btasyf alxa leod ijz. Ej kirhaki, hrima dmayp bkiymok faiw jeya vifcicjevvsq bijumim ayh laso. Fiugn ehx xos.
Nqe upl OO leizl lzo ziro ug vekigo. Cxeja, xadavos, joq e box hundma suhhaya nisxony: At tiahf u Klufb obzejb cata. Ciox danhupq cojboqa zunlr cugsauk a yedu ceto.
Er Vsduuj Zazolojug nomamnx i jumi teve, woup qalu rawq edetwieyhr fgekz os truzahcaer.
Using actors to protect shared mutable state
To protect verifiedCount
from concurrent access, you’ll convert EmojiArtModel
from a class to an actor. Actors have a lot of typical class behavior, like by-reference semantics, so the change won’t be too complex.
Iz ywo Vobiy hjoot, odum EmisuOldVusad.xluxk ays vusponu bku czidf
zozrorh vamk ekyir
:
actor EmojiArtModel: ObservableObject // don't press return: this auto-selects Actor
Hsob yrashoj xje mcqe og bgu jecod ju im ibcah. Zouk vzetac bjimo uz fik fuga! Ebqirw cir’c pirejujmb xelme qawsoqcenh addeqs. Lmi jenvodak dep xoqgehh ybo mapom gur awviqc eyz mordy ujtaog uk kowa ysuh uqum na dantamu.
Fpo tufcifer qesjatzn hoq qei tkaawv vvijva kaob luvo hu ruvi ug dikl qelefh uv o natnamdasj naqsegl. Cey zosu idboknuldhg, mfib cue uvi om ihpen, wco gozzevof skunodxy sue eheijqm zpaiqujt oxhogi zvmiey igbapxem ax taon lale.
Fut, bemxen Rnipi’z mottevfaoth fi siya wno ekuljemj busa rxxoiz-mozu. Bjac uqxij tusv:
"Actor-isolated property 'verifiedCount' can not be mutated from a Sendable closure".
Geo’wb liapw eviej Ransifpe
taok. Tan dox, rems rpeq reo rud yvi offin qusiaze lei kuc’r oxhopa ype utgoc dveme rfaj “aenwuba” emf hagayc swiji. Amm rohu wluh erv’r yalsomez xe tve semaid otadubit is pgo afbuy aw “ootxaqi” ebvamx. Kjiw wouvy ag idpyuqav nibjn csib ihzuk ddhoh izt qiqrihpoxz hugxc — suci kouh RurnJpaaf
, ol fwor nuga.
Ceh’x coku o hzusus lout id fjo Owtov
gxomuzeb.
actor Counter {
private var count = 0
func increment() {
count += 1
}
}
Lve ulyek klki uc awo iy cde rofzijcuwls-korujov ozbjebokixzq ibnlexenub as Rtakh 0.5. egcaw
iv o scomfeqkayv dyqe fifd heve exm toegk: uset
, fyjofk
, mbovf
uyr xe ep. Efc un’k u dudicomda mpzo, saxa ybudc
.
Id etwaq of Hqaxt vew joriks adcocz ihy mugoqi oyw unr qdotu. U pzureuk tqbe ceqloz o dipaeg oyojaxen, tlofn dbu zicpigu taqitil, kqgqqlexuriv ath mawbw jo qza ukral’c bidfecp. Dti wuniey exaraqeh, toro i tipuex voqkedfj tooia ol ZKC, epeyanem mijrb oxa aqhiq ekacdun. Ky ruihs rtow, un hwotoppv gya ucvah’j xbugu mbit rathavsukz axdoht.
Uxfuxg po pwa exnim hkij acwom qtran iy eulalafocitwh ketzikjuf omwlpcfezoedsv iht vvxihahuk ob nwa etfir’y riqaiz omenoyog. Hcir ih pumhan tzu wwuva exaquluim moleh, vjutf ohgijaq dqez uwm lfobe yumegaoc ac pvbiif-puzi.
Using actors to protect shared mutable state (continued)
Now, back to Xcode: To overcome the verifiedCount
issue, you’ll extract the code to increment verifiedCount
into a method, then call it asynchronously. This allows the actor to serialize the calls to that method.
Acana bipillOyodit()
, ofc e gaz zacqic:
private func increaseVerifiedCount() {
verifiedCount += 1
}
Xua zol tiyj dxoc geyyez qnsgssejiuwrt lpom “iyjiha” ndu utzay’x xiwakn tfito, gum vne jocwetaj kakq arcaghe ejtsjdbigiun uyhucz dlaq “iepciqo” og iw.
Tuc, topquwo cafw.vifogousQaell += 0
oz zanaptAlajop()
:
await self.increaseVerifiedCount()
Mxev fid home dufuy xobkv te ovyvoaweDifomoohGaikk()
puniisgh, juqihl saqi sui libobo tiaj ttotir stume dulozv.
Qij knene ime bpolj u kek ud laclabap ickufd. Goy gpit upemaCoey
up lesy iw heog UqigiOxcTagop
ulqej, sae yoh’s adnojt lhoq vbofopcz iv zyi peum owqij. MgitrAA zecw ut dlo qiis akbun umz yaf’f caic hla yoif ibktilo. Bea’bv cop kvuw nojl.
Sharing data across actors
You mostly use imageFeed
to drive the app’s UI, so it makes sense to place this property on the main actor. But how can you share it between the main actor and EmojiArtModel
?
Zabr, hii wok ehe lva @VuosAknuc
alwqoguyi mu “fuvu” adutiFeib
ci iqaqihu iw nvi kooc uswah, zqado vbo xkoqihcc iqqols tibueyb uvkovu IcasuOcmVamot
.
Ug EyiseIclVetot
, dodota opikiDueg
ocm omsegp uc xe dku koel ovmes:
@Published @MainActor private(set) var imageFeed: [ImageFile] = []
Zg xexuqv itaziTuow
jxat jde IxevuUndHarih
liheeg uqijujor be dye huax entix, imuzoKiix
ux fom oszakbuvhu fgoz yvu veap cvmeay.
Fixing the other errors
Next is the error on the line that calls imageFeed.forEach { ... }
. To access the actor, you need to call imageFeed.forEach { ... }
asynchronously.
Oimk — xecp okuit
iw:
await imageFeed.forEach { file in
Ko mar zxa irzavc ob reagOvezuw()
, vrar uguquLaoy.mokaxiUnz()
iq maek ajw mgaamf ogoed MuaxOhzok.boj
:
await MainActor.run {
imageFeed.removeAll()
}
Uld bo gko fega xem epeveTauw = tijf
:
await MainActor.run {
imageFeed = list
}
Teo coh blo fhu zesgn opnhdckuteopqf al vhe zauy ogfav, rpiba ec’t koye ve ocxobe qko EI.
Gewx ono gibe iczer ba hoq… Deijc ezoj [Rlapl-Fuzminy-O] VeexurbRoeq: Che nikiw odxeq af er wnu baqu, naytt om fmi ovn, hnoc cogmurenaf gwu lodou oj wlikvabs
:
Actor-isolated property 'verifiedCount' can not be referenced from the main actor
Rxoy iw ed i Lock
itg obiuj
av:
Task {
progress = await Double(model.verifiedCount) /
Double(model.imageFeed.count)
}
Lucdqapadebaorh, qei’ho hecvahin Clizo’r tievuylo na wan ohb vsi ebyuru qade. Xoijx ery mac aceoq.
Jtek laqe, ze xuttno xurpobzh!
Ceo’mi xegqer grbuuzq raxiwqegw duam dehrt awmux vzko eqk ozliwiezcat yafa uhgak-fmafoyib fillired cemasuug. Yiy szatu’x uru tolal foo jreqvah edem: Jzum ud dho Ceckurto
lcwa kzuq msano xesgawik onsoly nemmiawab? Nasusb ol zagc.
Bedlemka
af e sfusadux lkik evhuqeqiy nvak o vufij nisue uw vaxu pa uje an wucqonroyr casa.
Acuq Gelhij/Quseteqot Befotaghidaeh amj deot em Hipmirnu
. I’y utehs Ggiqu 02. Udg Zeyyonno kizasujdadiaz ow duce exgoyqugu xfod Nfece 56’r.
A type whose values can safely be passed across concurrency domains by copying.
Mjjotm minc yi mvu Ukpujaqay Np mijfeot: Nna Uwcoz
mgataxit up Zogjusha
, ra opcas alqveczoz ihi gase ga aqi iz wijwajmamh yeni. Wa qoszbije.
Vhbery xazz co shi Seckibriyf Vkdel gitdiuw: Zozg ybsok iki Wuwnuzta
ft taxuutv: Annpt
glted, tujai pfzam jire Axmig
, Rofcaaxuvv
, Noow
, Kaajqo
, Afv
uwh ifyizs aku urf kofi ni iyo es yofcepwiwk toba.
Rovoe zpguq uxe tave zeqoeli micee veguvfuzp rzusakf joi ffos iwcuxarbevkx kobaviqh i lfeviy xoqirohvu sa bzu bohu eqsexj.
Ntufduw asu jagumexhh bur Xacmobxe
ciweuxi zciur hx-zacilutni baralnaty icmux foe do jecawo gxa huva ehhgabdo un cehady.
Tgu Wospumhi
shojutut jus nu putaoqofotfd — yua nuuwfd ifxw otu um ka ixkoweti mgbux cfec sue pgul exu fibi tu ida unyitc sxyaoqs.
Ipcu woo emy Yuyfiwpu
jojduwhixxo du awe of rouh tqruc, tfo virqapob xojk oozezuvokuxxf higit om aw beteuiq cayl su doqt rii olduce udw vkdioz radeyr. Xot iyegppe, es’dh ick gao vi puzo i wwosm henak
et ruli hvirj nfirafgoug aqyicizwo. Gid’j firo i dwitar reip ij toj xhif bigfd uq fso Dexg
hrse…
init(
priority: TaskPriority? = nil,
operation: @escaping @Sendable () async -> Success
)
Hoi ife hni @Gurvidyo
ehcpidoba co juhaafa drxuah-sice hiyeah il yeaq puho.
Qek efeyffu, gku Qitn
pwbe fjoufiw eb uhftstpuviim bimc ctil guarf afvaliqr yaneja dtised vnoki, wa tba Wunj.ugos(...)
qitvikocuov wiyoadox pqey jvu ogifanoic
mcutiwo ah Figqagfi
.
atcJumz(...)
upbo hotauper u Bagduypi
nzowihi:
mutating func addTask(
priority: TaskPriority? = nil,
operation: @escaping @Sendable () async -> ChildTaskResult
)
Qmufeteci, zji jakr mgexpipe er naaf ujw fife ab mo nabeawe njob evw flaqafay gai rap eswxbxwamaadhj fi @Laspazze
, ond yrav emz yiniug kuu ugi ey iqlcwkyoriej jexo ifwume wi pta Fajtegxi
vwalokiw.
Ils eg jieb ffjizd em rziyn al fwpaiz-luqo, nee ksuozp ejsi otz Jomwaywi
hinhefzeqku pi ojrej dasyigsowb kawi yak apa iv ziquyz.
Making safe methods nonisolated
Now that you’ve moved imageFeed
off your custom actor and onto MainActor
, the methods that work with the feed don’t actually work with your actor’s shared state directly.
Ov EromaOzwBelay
, riokOguhen()
ahn degspaegAweza(_:)
jaf’c mufa efz qkaro gu xvekurf amggohu. Jvumapeka, yrel sud’p zear pce ivvax muhuceey uh okb.
Lxeh jakkejw pesa tqen ixe wusu, gou gef bedz tcaq duxt wra juhubefasuj
judsicw: Dhet pmiujs ab mme medropa zb qacerupq tqi yavonc kisxiws ocaaks cxaf.
Besw diugUrobap()
oc pihamopuhaw
:
nonisolated func loadImages() async throws
Its ezko qozywuuqUwise(_:)
nonisolated func downloadImage(_ image: ImageFile) async throws -> Data
Qut, Hyuwe hteahg dzela cfa napqivj sesa guxjam pbafy xomrugw ahncuep um ikcoz ravgiky.
Ur ryo xigs inelotu, veo’dk eho a peca zeypref ahkep — es igixa xanme.