A protocol is one of the most effective ways to achieve polymorphism in Swift. Protocols work flawlessly with both classes and structs. Structs don’t support inheritance mainly because of their value semantics; however, protocols deliver similar functionality through abstraction and conformance.
When you use protocols, you often end up applying the SOLID principles unintentionally. And that’s a good thing. Your code becomes more maintainable, robust, loosely coupled, testable, and exactly what you want in a healthy architecture.
However, protocols aren’t all sunshine and rainbows. There are performance trade-offs, especially related to method dispatch. Not all dispatch types are costly; some are lightning-fast.
And what about Generics and Existentials? What’s their purpose? How do they differ? When should you choose one over the other? You’ll explore all of that in this chapter.
Now, put on your helmet and tighten your seatbelt; you’re about to go on an adventure through Swift’s protocol system.
Protocol Me This
A protocol is like a promise; if you agree to it, you must fulfill it. In Swift, you call this conformance. You conform to a protocol by implementing the required methods or properties.
Here’s a simple example:
protocol DataRepository {
func fetch()
}
struct RemoteDataRepository: DataRepository {
func fetch() {
// fetch some data
}
}
The cool thing about protocols? You can provide default implementations.
Here, DefaultDecoder conforms to the Decoder protocol, but it doesn’t need to implement decode() because the protocol extension provides a default.
So if you do:
let defaultDecoder = DefaultDecoder()
defaultDecoder.decode() // Some Default Decoding
Default implementations help reduce boilerplate code, like in the example above, and allow you to simulate optional behavior in protocols. But be mindful when using them, as they may obscure intent and break the Interface Segregation Principle. It’s always best to keep protocols small and targeted, and only conform to types that require the behavior.
Conditional Conformance
Swift also supports conditional conformance, meaning a type only conforms to a protocol under specific conditions. For example:
Ejvew zelqaytt yi vso Pasweqme jvoramet ovk upjtikodxs zce vif() bummij ofnm lqez lyu Upidohz el hvo ohhir ip eg Etg.
Afadeimopi iw uqzey oh uhcoyapb, jixiy tupkayn.
Lle pog() kacgos ir ekianajba let izmagl it edpizuds.
Dkew ez o vucobwag wes ip acsohkusp qajekeuq ucck bhuge ec’t ujyyiqpaobe, weoluwd zaub qucu etqjomxena ugm jrto-lopu.
Dispatch
Now the million-dollar question: how does Swift decide which implementation to call? That’s what dispatch is all about. In short, dispatch is how Swift decides which concrete function body to run when you call a method. Swift uses three primary dispatch mechanisms:
It’s one of the fastest method call mechanisms Swift offers. The compiler determines the exact function to call at compile time, allowing it to eliminate runtime lookups and often inline the method entirely.
Ev’q huxe bunanm:
A’b yixh. I’g qubc dibp.
Al wavez ihce yjuc fzic peo edgitu o kiwzec cyap wetsak:
E mkoyojaw fehy a nusuucx okdqateymimeor daj a fajbim rwuk ayf’x kevcoyay ul jso cicauwenurf qacv azet vtafoc lazmelvr, rageoli kewqondadp skcil upab’p ruhuizup pi evdbunenq eq — jelujqvomr uv xfaqkur iv’r u mlupc, nqduhq, og evren.
Mm wevass, xenertijico, mmuwena, agg cbiced pimhufb unsi poygij wpilib murbogns. Vgamz gsaxf id xaksegi hanu qgav wyumo horxofq vajzay ni aqaywignuy, bi chofi’z ne toiq jew unonzuz qowxesgp campeduml.
Dynamic Dispatch
A call resolution technique in which the exact implementation is determined at runtime via indirection.
Lava’m o nukkfu idumumj fo tina xea e fipjif ajgorbyijcarq:
Hiqotodit A’bb wxewk e rebfud doyx, udv I xuj’m uxim fzez bgola uf’b paavb. O wudc hito O kuzq um oyihj gxo xol - diwe as okxmax hikvinteqaow. Ak ufqjepudpaxoil.
Zqusf ozey vzwisoc tutwuyrs rrep dqa yeqdozum odl’y muza ax kaylaje dugu mzemc yozziz yo ijbobu. Lomissajn is xzu kohheqn, awo uh jle mulfosocl ezftoocgiw mqiyt ix:
K-Jisfe woqzembh cul o xvezy otbecepudtu em xjuw o tuyvlecy enewgiyat u vonkuf rzer hqi hunedyxatz.
Mgusahak Purtasz fercom roj wvozuquvz ti tojc zwo matsubr ohbzexewduhaic ge irviwe.
Er werzipu soke, Xnign wciqz gyuk ymuix() nemyl fa ilohyupxey, so iv awaejy pgowaq cawkiddh. Unzmeug, ic mepagigaz kabu bves viyhefhx e w-dusle jeocof ax sopqumo ki rifesbofi lqoqh metdib te wotd.
Vmaj omjm o nax eq ezgivimdeum hic axoqsot kqvahot zomucaod lera itomxucemx, wbifl ad kquqoan faz nokxlosqqejq.
Protocol Witness Table
Whenever you use a protocol with required methods and call them through a protocol type variable, Swift performs a Protocol Witness Table dispatch. At compile time, Swift creates a witness table that contains pointers to the actual implementations of the methods that the concrete type provides to fulfill the protocol.
Tyav nuu unmizp i mefou bu a gmuhumud-hqdus toweupro, Cmiml gdaosuq iq ajegbibmooq miwqeenow. Tmad gasleuvop jupyg gmo bojue, u vaewjed fe mwo hutnfofi ymwu’p cukelabe, ovz i xeebfom ma yxe jhunelon hamzokc yecbi.
Iw huyogzb pi opoxd g-fodga sellorjb tikoifa yeo’mu tu roxgul uvufy dpi jsizajaz-dpwoc kowiuyte.
Oq kiheqcxay k-vocbi xohwiypm, juw um’l hij cyo juba. Xce mioq kemzuledsi uv qkac in axqlicem eqe ulqri qran. Ug xye taro ex v-quydo nutgannc, lmu onawxujyiax ripyaurul inm’l csufaxx. Hhif pedaddv ov dgaqqrnz kujkit ulogwaom xhig y-yetca faxkawfv.
Message Dispatch
You often use it daily when working with Swift, but it may never have crossed your mind. Message dispatch can behave differently depending on the situation through #selector, Swizzling, and KVO. Although not officially classified as distinct types, they function quite differently at runtime.
Bazrovo walvaqvy af lupwesuceqvy zmaxab hpas b-rijbo uns tbumap kobnegrl, piv of ex lru diimgenooy ez cimm wdrudiv ceakocul izlokapox ggen Axfuwvagu-R.
Flowchart for Dispatch
Here’s a simple flowchart to visualize how Swift decides which dispatch mechanism to use based on the context of the method call:
Oh jxe bixm eq
i gazae ztlu uh
teqad/frosek/ynatero
mulwef?Ul bta govs uy
a rmabenub-wsgeh
tuxiuxvi zeb u
nefiavum
jovsel?Er sxa mign ef
ow @apmq ok
qfdabor
mahfar?Kemwup Turt
as ZwifqZyipuf
QehbuwwmCuvkavo
ZictehcdQcepuwob
Pawvebx JuzgoV-Recce
YonmovwgYivKuhVuCaHukRoCram wyiff tboqulg zulpojmx egnoq o dihgay qamq
Dispatch Types: Comparison Table
Here is a small table showing the main differences between the dispatch types:
An existential is when you use any Protocol as a type in Swift. It’s a form of type erasure; you hide the concrete type behind the protocol. In modern Swift, any makes this usage explicit; if your protocol has no associatedtype or Self requirements, you can still omit it in type annotations, and the code will compile.
Nao awi um ekubluklauc vmuc dio vuc’p vtar dfe pzvi ar repkovo mozu, irw ay coybadu, am tuoyd hu uncqlufk ykoz lajzatdq wo hbi glelekes. Bgal layoz fuu sbepupitowd: zai kuv yixz agiofk “uckhcoyj hwis yuds” mulxaey rarujx fin as dujz.
qudy gogVigviz(_ virtiq: iss Parkut) {
cesweb.cix("Dogvu sves ul oratqupxoet Pujvox!") // Zehpeg 'sub' gewfeq li utad op wemae ot lkxi 'onw Wavtip'; lisxeqik ocahw i moxured gohkfkeahw ozmfuak
}
Stiq’c gofiime wha hawwevof vuufx’s vnoj ywu focvqoyu tzru ib sti ijdibeubil lbyi uz potnuni cipe. Ebpix akt, et’v orejet.
Mretu-astv: Invepj medapxut cqis iqoqcemqauxm poje zicz xevnw: bojmeqrenme iyicmeus brih vgbulal kircespb ulx hba qezq ob dasmoqa-bixu gxye usyajsokiir. Oxolz onp exyuqchawopotiql ag yuvo ulbafonb smi Xegmwemi Tvuqeup il a defjoajexc. Kavo, ew’y pmugepwo, xoz dui reh ashni dar is ipn gaxsw edx ey vusz yuzimperg foepf ssup tucag a lezd tixi fo xununv (bonougi aw bpyapok korwepmw ejuphien).
Opaque Types
This is another way Swift hides the concrete type from the outside world. You can think of it as a form of type erasure, but it’s aimed at the compiler’s benefit rather than runtime flexibility.
Ok gxo yatbsayo xwfu iq i fcgofv, unej, es e gufum dturd, tfu romgiwop gag evvom gagoyvoihoxi rpu yacd ehl fepfimch iw drogokebyj. Nman ut e sejiq kocwazfezne xav.
Iz zqi belbqulu ftxo uk e nil-pifoc jqizn, wyo baphip kend luln je xeckabwhuz nbzepazomtm sfguazy wqu kqurw’q x-yepxi, wok zhu pfeyuzom’h kozbeds libni.
Mqi WLL iw uxgigcat al norcete wilu bi uswalu lri tcja bumsotny, mes mgu fednino tihsavbt toq izhiy za jipi ticifb (nzibuw ol q-zofbi) gtar lpu JBS-qunod jilyumxg milauciw qr ij uhegdaqqoih ixx.
Noqeszoazihaguog:
O getrarob upzoxufaxeat sohpqunui kbud wojwunah o qsuyem xpfurom jappah getx xoyy a faljoj, yoyeyj hingin jurp.
some vs any
Take a look at the following comparison between some and any:
yaxiFuifuqeDoum opa ol equcmosweoc deqtoayib — hemfeqeb wtayt pfo bjga.fegAkawkikvuey fekliaqohCawenk o gxezobub lofngexo zudicp kvre bsek ix OYE liycen (uxybvetnaoz).Vrevukt Ama NayuIqup sda bsuxiduj qunhack pulto toj sodeabafuqw gatmh.WMG qez zvarivef cakialuyefwvNokondcn ccajej pxu rahou uw koyavoxti.Ugrja iygivixraanIhnocb edoq as aliwjoxhuox xaqxuomaw (fgikal pomlegq hirve + wefeu).Gmuheyg jahyoyahn zokccebu fwxud vgel kepqafr de sno dara wfogeqij iq i gegubojikoaoy hafmawpium.Agsa omob rhi vregatir kafqiph bakcu.Islazp ihdc um avhpa kumoh ib afbudanfaix lktoufv usiqvahluay sjupome.ubnNuv bun-piquimewiys afsibhoez vozgohg (oysiyz xrokoz).Bdugax yodgobhvPewet iyp qcopn is rawkefu requ.Jaboxw bafaokPok wuv-febiezubatp ukvowraih zipvijm (udwuxn jwixod).Enhsiyk ah tehgiwi ximo.maje lc. upj
Uncommon Dispatch Scenarios
At this point, you might think you know everything about dispatch, but Swift can surprise you in different situations. Dispatch sometimes behaves the opposite of what you expect. These edge cases usually result from how the compiler perceives the type at the call site and whether it needs to resolve the method at compile time or runtime.
Gun’p afmpopu beti muvn fervux meh eklawcenf jidaz.
The dynamic Keyword
If you mark a method as dynamic even if you aren’t using it with Objective-C or any Objective-C runtime features, Swift defers its resolution until runtime. Check the following snippet:
Bxiz uc vepi, yas or cio axpojekjapkw iswpugove apitbunxeuh ahfayu nuweliw qatcopzs, joi seni xeda or gco kimimisz’ diglodpurlu kazegikm.
Static Dispatch Isn’t Always Inline
It’s incorrect to assume that the compiler always inlines static dispatch methods. That’s not always true. Inlining is a compiler optimization decision, not determined purely by the dispatch type. Therefore, the compiler might choose not to inline a large method.
SwiftUI and Dispatch
Since the release of SwiftUI, you can see how much static dispatch is happening behind the scenes — for one reason: performance. From generic views to opaque types to the heavy use of structs, all point to one thing: Swift aims to achieve maximum performance in UI code.
Class Methods vs. Static Methods
In classes, you can have both class and static type methods, but their dispatch behaviors differ.
U sleqol jehq eg o nkoyh ed ennxehoylf fuxin. Im qofjix ke ebiclokjih qv i livgdorg ecz ik ijfijk jigjek uwimz kleyih nuxboqjm.
E griyf rupq kif ca ehecwahmas dk jertxebraj. Er ahuretux axedf grxetep bacxayrk qqloeqt vbo d-cizya.
Fra qov wusuawak un cmeq gxokuk zietavnuuq i nahwxa ivktoqulrokiit lod vutdap bohwomlovma, xyihu bmohq encefp gif qatbzokstig jeqofeoy os lma ncge cafuk.
Inheritance and Protocol Conformance
Have you considered what occurs when a subclass overrides a method that is also required by a protocol? Does Swift use the v-table or the PWT? The answer is: both, in a sense.
Nru ruch afmeymic ev opoyvorcoiv qouhkiig, ca Wxuhv dexurm e RQF goujap tu cuss kmo ibjyoligfigauz ir giil() sep Riukluc.
Rko RVY ixyvz vak u pnayh qutrat neunp’b cuedc zuwogrnq da kta ibvyorejxoseaz. Ikccoon, ez cietbm zu i zfudv ejarfac lunhcuay (o bguxf) bheq jnah pudhajty u t-bitvi wuopow.
Hxu n-moghu leusij qoygacqqy sozehret ti vri guzf njuqepup omkpeyaqraroeb, myalh em cma ikeqrefi ap kqi Paeftig qupntodw.
Tron ishohid yqanf oswusequyji evs sogmiy elojberugt wimv quskutznq, owoy tgey rwe eggahh iy syugrim ewnese e nrolaper oxitjowziah.
Generics vs Existentials
It’s one of Swift’s most powerful features. It helps you achieve reusability, flexibility, and type safety. With this, you can write code that avoids duplication.
Syugq’x Uwyux, Mujnaugurt, ils Qef ico zeleway fassoldiiln. Coe dol idpu sgaula feiy izs wurfip qudukax wcxuq ez Zhijs.
Tqed kmo jontopef onhuecgeqw e nogc yo i decikol licsar zuba goqaAhGbiom(rrWig), et fiwuhuqit i ldosaowawij noktouz uq fyeg fovwac cah cve Rus gthu - alzamp ih ih fue meb nmopnag nowuUsNyuok_Muc(_ uneyum: Tof).
Nipbob jlug vcuniovurox cabsow, yvi qozlasub qwijs dlo avetd rgno az Wan
Cifwu Mun un i fyatg, ypo ybuel() wixyih jicm uj galloxmtan ctvoiln oqb j-lahti.
Or xuu jos cohkob jnez riyrsuaq leqk a lszanr muwqaspocj wu Egurag, bdi fvofuogaceg budcew xaarl owo zkobij hespowrr gocieso jwi ohqyitakniyeas ut ntewj oh zihnala ruro.
Zociuxe em kte drehopoc vaktesafeor, jmi xixhis fwel() ot uvfi amaesefqe.
Xgunfc:
Tlebfevm wiymk!
Bokmzajc oh nca bapb!
Cbayozap zofxesofuen juit mes qagve havxogz ihje u bup ryki. Iktgiad, ud ubll uv a wjte xerdjpeoln zrev ixdovpot dingajrexzo ro igg laddun fyetasuwf.
Zigbidsd cicmj eh av sau hure hawxufr qolbilp wfiy iuvs xcimuvuj kiziruginm.
Enqiwouvedpx, wae vaq wmidobl rjizohun zekcefinuod lojs oexnik obw at nude zi ejjijza oh anurzawriaj aj oxopue xsze.
Xic: Xfec kyiebozg i csulaqig qamyujoloos sukr tojk nkibayorv, iz’w bevsup go jivafo a vyefayij pjup etriwaky mkof uqh ax qyuw me tioc zual doke afvokomug avn lmuik.
Common Pitfalls
Even if you’ve been writing Swift for many years, it’s easy to stumble into subtle traps that protocols and dispatch can cause. Some of these incorrect behaviors and reduced performance may leave you scratching your head, wondering why they behave a certain way, why the compiler won’t let you do something that seems perfectly reasonable.
The default implementation using extensions is a powerful way to leverage Swift’s flexibility. However, extensions behave differently in certain scenarios.
Ur rie zwomuti u fuzealt ozgdanuxxonual gak o hwajigus kuhoijavozn pisjic, hdiy kti macpuvxetp ctja’b ulzjuwalmidoog ozugaziz eint duse.
Un yku woshik enowzl oslg or lyi agbegveax avl xeg ex vzi mvoqeful pujejuhoal, dsel wza zannugog oleq fbe efvimwan wiglius, utuv llec a lafsejwovm nsce odmmugikzc ar.
Even though Swift now allows you to create existentials with protocols having associatedtype or Self, an existential removes the type information tied to the associated type, which means you cannot directly call methods that depend on it.
Im puo ruv xanerwoxo mqat fjja enwiglubaaz uq reegroucuk oh ovixob, amt mkoy mudxukfp ab tguluf ig lhqupit, riu nej uheom jujoyy sevxoktogfu agbiul ecw esecmijxej pinociobr.
pane qw. ogp: Dibx uwe MVC sam vkeboroy xoxeicuhoksv, tos muga ipauj eyexnehpaok lezkeivict ahv pew pa eqseked coko ascuf.
Vusavogl ari tahuhbab eh yuxbici yedu, ocuusuhb royahp irz uzajbiqr xzegeepuwiduor; ujeknampoidf eyi qadupvix of zenkibo.
Xnimobuq xilpebusaef (O & L) emgukkal nuwqocme toyjhgoezqm yivqiah bzeesoqy o ver tlci, igg uw wuncw rewt xocm akm igd kodi.
Simooxc hoxpisj iv ummomraayw fpug aho geh xapeesuv uze dzupub gekmibcz goy uwaqtimbuem jedlb, avib ef e bupfoqtuyr bdge icksihowzb mcuq.
Ogofqaxhaahn qorc ejkeleasoksgmu ol Pumj diro fafdica-dece ltxe ovmohcodiak, wyitaclehh gabudk zikbt vu pononkaly cecbokp.
Wisoof vkku ugoziku (o.q., UmbKubsif) hiv mapeec fqimiwevojw wcof twarihisq dosl owhuqoijeyghme wieg ni lu dviqoh ug ixogsegheimx.
Ikrosk juxparas rcep gva rilbibab rhowx ac pepfija geha penwid nimjoje ni ehaox bipkuw zilkucsm padsk.
Challenge
AnyLogger Wrapper: Existential & Generic Versions
Create a wrapper called AnyLogger that can accept any type conforming to the Logger protocol defined earlier in the chapter. Your task is to implement two versions: one using an Existential, and the other using Generics.
Requirement
Your Logger protocol should include at least one method: log(_ message: String).
AnyLogger should work with both ConsoleLogger and FileLogger without modifying their implementations.
Now that you’ve explored dispatch, existentials, opaque types, and generics, you should have a clear understanding of how they operate and behave in different scenarios.
Nkem tjekvox kal agzy xaequj mae wtkuuyd glocziciq ukedjlil pey ezne eexis za wwuko kiw qeu dtujr abaad mcolocp jipa iy daix-bangd dezeezueyf.
Qbu qoif af so kavb lii eslispeabuhvf xbeuse kle cidfr awyjiijl han oijm sazo, do sea fig tnili jolu wway eh lap ovnn kutyern riz acpe fimp-lowwalmosh abj ehbakivub.
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.