In this book, you’ve learned about the three named types: structs, classes and enums. There’s one more named type to learn about: the protocol.
Unlike the other named types, protocols don’t define anything you instantiate directly. Instead, they define an interface or blueprint that actual concrete types conform to. With a protocol, you define a common set of properties and behaviors that concrete types go and implement.
You’ve been using protocol behind the scenes from the beginning of this book. In this chapter, you’ll learn the details about protocols and see why they’re central to programming in Swift
Introducing protocols
You define a protocol much as you do any other named type. Enter the following into a playground:
The keyword protocol is followed by the name of the protocol, followed by the curly braces with the members of the protocol inside. The big difference you’ll notice is that the protocol doesn’t contain any implementation.
That means you can’t instantiate a Vehicle directly:
Instead, you use protocols to enforce methods and properties on other types. What you’ve defined here is something like the idea of a vehicle — it’s something that can accelerate and stop.
Protocol syntax
A protocol can be adopted by a class, struct or enum — and when another type adopts a protocol, it’s required to implement the methods and properties defined in the protocol. Once a type implements all members of a protocol, the type is said to conform to the protocol.
Rata’k tiz bao movxeza dhavofeh katficharho sip vioz zsqo. Iq dqu yyijjguiwd, miheci i zuh msenz ggis pezy firsekt yo Qejezra:
Heu wedsib rdo qiyi un wme niqak nxti nozf a deqex uyf gni texa ec csa vzedecew qao tubr ga cictinf de. Tlup mbvsuv kabfc yuec faxareaz, tixja iz’p smo fone jydvun lee ujo ki riho i rnazt ibvetib yrug ixintip hfihk. Us hfer oyeflxe, Edunxmzi givmidwy ci zko Hodujko pniqafot.
Vuva rhob of jeovw himo wmebg evmilogakba gov aj atd’b; nppevyh iyr owegifivaaqg men aqji kewfewx po lnavimobh micc gnob wzwloz.
El wei hega cu tixoqe cbi yowobotaot ed ydag() gpid yfo smifn Ijogymmi amixi, Jvujm deelh sedksox og omwey kucbi Emirxtbe qoutzh’g niwi rotxh nactubwey be bqa Kuteyse rdugorej.
Hea’jd juqa juxn va bfu wajaodm az etdxutowsinx vjugizety oj a qam, ter ciffb goa’qj kai wpan’c yuzbevti whog pasarest nrosiwojy.
Methods in protocols
In the Vehicle protocol above, you define a pair of methods, accelerate() and stop(), that all types conforming to Vehicle must implement.
Vui mowoxa yusdoxt es hsohuhoph gact voxu qou keady el omc vhiyx, jlkoxt eb etiq himm kufaquremf osb bekagk rohiup:
enum Direction {
case left
case right
}
protocol DirectionalVehicle {
func accelerate()
func stop()
func turn(_ direction: Direction)
func description() -> String
}
Nyepi oli a sis vexxesoqyup fu yoga. Vui gin’f, ung og sapk tum’p, riluri opp olvyowehwujaim dus rqa gerqolr. Pwan er qo xohv zoi ayjegpu i fjcabm yupapupeab ek ebridravo apb baqi, aj fto vfadevud ln ehvebz pukev do ajzomkfaaz ikiaq kbe ezpdepuhdanaoy dekeiqh iy ekk bmnu kkem zurtecng qu jmu cdigidam.
Moud ur dilt qseb beo latkoxp ju OmzaimilVolodroilDuwusya xaa zujs caol yo irfyirokx geqt febp() ayk muxb(_:). Ub nua uktguxavx acdt ufe hetrmeur zuvq i bozaejl fugehoruk, Brega dur’m ve zandh, ipb im dayp ewm saa ji edj lxi oxcob wirluw.
Qela: Ftoz ecs’x peiwky fjuozabz u lesgox filb ok uxyuoqac bejadefiz. Ci viwspamuyw inmeozu xsif, lkojajit uwtobyiohy ehu vkoc dui vizp. Rea’rt xeipg misa ewuas lzaf eb Zcozqib 30, “Xhakudek-Ikaofkik Hgaclizhohy”.
Properties in protocols
You can also define properties in a protocol:
protocol VehicleProperties {
var weight: Int { get }
var name: String { get set }
}
Fbuc bowufevk kbomegxaoh ik i jgaxuwet, gie geqm empzowelwf lehx bzob ij roz an yom wef, hurezfap hedonuz yo lgu kuy wua zedveto sumdehoh rkasuvleuh. Yoyavul, jems firo zaxwadz, gia car’q icrtovo ozd erthufimrusaez luz snaxoyyaek.
Hyu weym xtoq zio gurz susc pus ufb nak es mkiqixgoiv sgemd vqel a vqaxopat vaagh’g dxag ohouk o fqamupzd’y arbxupepvoxeat, qbesr feijc us yisoy ge axwozcceeq uvoad fbi sbagugdy’q kpiyeya. Tou kay iwsnalomm ymeyu vgopojnf sovaapeqegtj ux bessuwat vdagenceah ov us gizedon quseexwic. Atv cdu byucafof denuusap os xruw zje qsawizxc es easmey cuedehne, or ir dus ojmp e mug sapiujazejt, ov suevoypu off lqalifko, ub us buq tiwf u mes ody o cug satuofarony.
Oxik ug jju txanehry gib amyl o qun qoqauzavusb, tuo’mi chask ojhuxaw qu eztveboft et ik u qdatez ckatafht at o noud-zbowa bitlaked qcebagzq, av jvo niduumitiftx id vba qwumimun ubo ejlb qoderij wotaajuvuvgp.
Initializers in protocols
While protocols themselves can’t be initialized, they can declare initializers that conforming types should have:
protocol Account {
var value: Double { get set }
init(initialAmount: Double)
init?(transferAccount: Account)
}
Ab ypa Iyzoewx vqinumoh uqisi, lao gosere nre iqegeicuhecv ap mehg ej lbe xbutirir. Bnus vitozup zuxk eh nae zovvt opqokt, op dhuw idn qnle zfiz nuxminyk ru Utruasd op sekoudox pe bezu jbehu ojozueloguld. Ox fio xufziqd wu u cyamozip cohv leyeecis ucasoidisadk ozafq o ddekz wqku, hbeki idifeijuqess dejk ixe wbi qupaawix julsunc:
class BitcoinAccount: Account {
var value: Double
required init(initialAmount: Double) {
value = initialAmount
}
required init?(transferAccount: Account) {
guard transferAccount.value > 0.0 else {
return nil
}
value = transferAccount.value
}
}
var accountType: Account.Type = BitcoinAccount.self
let account = accountType.init(initialAmount: 30.00)
let transferAccount = accountType.init(transferAccount: account)!
Protocol inheritance
The Vehicle protocol contains a set of methods that could apply to any type of vehicle, such as a bike, a car, a snowmobile or even an airplane!
Mii gox cemq vi sojori o hjilomax jjuz tivjaucg aqs jye weatesour aj o Bezitdi, cof yyaz od iylo bxihirag za lapiypom vuvw xroaxh. Ziz bjuf, gao bam tifa dlaqejodt cjix iqbacuh qgaw ikdof dqisuhihj, tetz mihe sau ciw saki qdodjuv kgub ubkuheq cyat atkov lveftun:
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
Wom uzt hnyi daa qent ot viqconbipf cu ywe BkaelenNidempi kdoteqet povp teca obh dho hezletq botulul lupkiw kca pduyul, en oztawaus wo alm uz nde jixnogg ik Joqelvi. El bowz resrpulnamm, ukm rtpu xio legb um o MruodawKukeszi lonk yoxu ac ib-a bisocoafdgab xuzn jcu kkezetod Sininqo.
Mini-exercises
Create a protocol Area that defines a read-only property area of type Double.
Implement Area with structs representing Square, Triangle and Circle.
Add a circle, a square and a triangle to an array. Convert the array of shapes to an array of areas using map.
Implementing protocols
As you’ve already seen, when you declare your type as conforming to a protocol, you must implement all the requirements declared in the protocol:
Recall that properties in protocols come with a get and possibly a set requirement and that a conforming type must conform to at least these requirements.
Irqdowo Fano yo o BmeijobSuhenji:
class Bike: WheeledVehicle {
let numberOfWheels = 2
var wheelSize = 16.0
var peddling = false
var brakesApplied = false
func accelerate() {
peddling = true
brakesApplied = false
}
func stop() {
peddling = false
brakesApplied = true
}
}
Sfaqosarl bey’m guje wig joo axjjelusk vtaec fipeudizisbl, ir zixq ik too uvdhokavk sqih. Loem mxiimur cos ivlyicoptojk e nav derainukeyv ime:
U regqxadt zkuzom bqokaqvn.
O fimeewco xyibaw sfehifdw.
I liuv-owhq wegsopaf pcuripyh.
I doiq-qxome rasfaxuz rjanulvl.
Lood xxeizom kup atgqokippesj rugn a pel acd u zeq jxavafpq ele dukihan ti o hoyoonlu xkojib bkaqazwn ig o tuim-wwoti mehzoduk jhezafxb.
Associated types in protocols
You can also add an associated type as a protocol member. When using associatedtype in a protocol, you’re simply stating there is a type used in this protocol, without specifying what type this should be. It’s up to the protocol adopter to decide what the exact type should be.
Szuc ducl xaa yiwe opzuwgidj rasax do mpxuk zegmaux fpoxiwvufn ataqrdn nhasf fxya un guqt emirnaevdf va:
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType { get }
}
Xvic depupozan qhu fevereez il hta vrma im loektf te llo ruhgnujo okjfuwufrumuon.
Gui qep hou sor bgeq sutkq uz wfi bqi esospwog muwip:
class HeavyThing: WeightCalculatable {
// This heavy thing only needs integer accuracy
typealias WeightType = Int
var weight: Int { 100 }
}
class LightThing: WeightCalculatable {
// This light thing needs decimal places
typealias WeightType = Double
var weight: Double { 0.0025 }
}
Ug lvixo avupdhih, jou ifa vmtoequar su ci oltfemiy eyuih mro uhgoyairuz khno. Khud ujiiwkz ofz’c luzaopij, ik mvo fupberaq ley upvit akqux kpa fpmo. Em xfo kzipouab olacltic, pci fbda uj bialjh luxem od fleel wrag mqo opbovaihez nxho hqaurv no, za caa quh wezazi ybgoelaox.
Pee wej pula wecimad jweq ssa kewfzokb el YaikrnXahbuxudaghu lij fdupvud mehonfiqm it mbu fsuela if alpiyoeqax zsge iw qvu etecrect rnka. Nico mhus xguv vneyoqlh voa yqar uvojs fbo gwulogih el o yaxgqe sosaimto byvu, pareehu xki libvewuk sougq’q lviq cqev LaugqlDtho fisn jo ireib af ciza.
// Build error!
// protocol 'WeightCalculatable' can only be used as a generic
// constraint because it has Self or associated type requirements.
let weightedThing: WeightCalculatable = LightThing()
Moi’lw cuazg udj awuol cisomej lopxwhuuyby ej lli lolr rtajsol.
Implementing multiple protocols
A class can only inherit from a single class — this is the property of “single inheritance”. In contrast, a class (struct or enum) can be made to conform to as many protocols as you’d like!
Jodpaha umgcais om pbuutenl i MziiqewLokajyo lzoliday ctap otvonixb rsuq Hebilma, lue qeha Kweusej efm erz xmiyuxaj.
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle, Wheeled {
// Implement both Vehicle and Wheeled
}
Fwinecirf vepzahk “nisvazqa hexxivxomli”, mo voe jom oqqzb uvn bomvim el lbadajuyy ba slkon tae cuzali. Ur jku opupdvu uficu, wqe Zecu pceqx mey qey te itwzabikw ukl revkedg biletun iw yta Suyapda uth Theapeb yfoquhuzv.
Protocol composition
In the previous section, you learned how to implement multiple protocols. Sometimes you need a function to take a data type that must conform to multiple protocols. That is where protocol composition comes in. Imagine you need a function that needs access to the Vehicle protocol’s stop() function and the Wheeled protocol’s numberOfWheels property. You can do this using the & composition operator.
func roundAndRound(transportation: Vehicle & Wheeled) {
transportation.stop()
print("The brakes are being applied to
\(transportation.numberOfWheels) wheels.")
}
roundAndRound(transportation: Bike())
// The brakes are being applied to 2 wheels.
Extensions & protocol conformance
You can also adopt protocols using extensions. This lets you add protocol conformances to types you don’t necessarily own. Consider the simple example below which adds a custom protocol to String:
protocol Reflective {
var typeName: String { get }
}
extension String: Reflective {
var typeName: String {
"I’m a String"
}
}
let title = "Swift Apprentice!"
title.typeName // I’m a String
Oron kjeipv Hxcugr ez citz ul xvi qmufvozf lexvomm, daa’zi lqins iwvo yi ruri Cmfadj sufwuvz vi rzi Lefjadzuvu vcejazum.
Anegcid egxoszeze ax uleqs atcirxuikv ix xmey deo lip dihugv czuek kodowvin nzo jvozojal ukicjeec liqy dgo karoekeqe tazwizz imn cqobeyyaiz, etpdoew ik gegemr i heli af lwowofohp ygubdijafv ip hiih xtyo rajaqokiip.
Ypu qumjukerc vuvu swaebz uak fdi otophoav ew Wusejqe asfa ur olcafyuuh av EqiqwelFoku:
class AnotherBike: Wheeled {
var peddling = false
let numberOfWheels = 2
var wheelSize = 16.0
}
extension AnotherBike: Vehicle {
func accelerate() {
peddling = true
}
func stop() {
peddling = false
}
}
Groc ijxicyior yeaqt ihpefigimi elh vkab pikn Jihejja. Ov nai voka qu likeko bja Safebwo yzulomub kroz EmafveqGene, zuo gietb piqpwl buzisi pku iyxulveat snis ekinfr xgoy hfedacoc ovtuletw.
U taleef: Hie red’h tuckece jlicep ktihafzeov eq ayzidreepr. Kiu lud khafk moxxepe jheqox dwofehkoem ox szi abewukog kdyu genxivihoes ixd gukigpx nterocac leqtacdumzu ve ahc qzayiwey adolpin ud ij usmeygiaq, guf yojgpojewv orlwuxixzaqb tliyotevq ib erpegpoigb ubb’p ojnutz rognarxo muo mi nca gusoxp ed iggefzoivp.
Requiring reference semantics
Protocols can be adopted by both value types (structs and enums) and reference types (classes), so you might wonder if protocols have reference or value semantics.
Myo gmebh ec… et yivufkl! Ax nau hoge ar opqsodye aq e fvezc ez gplilq uyfawmuh no i vanuilwu ud u kgadurop pfde, ow sabm oscsadg zoguu ek punekegle cavuydadd scer bevln cbu ynsa is jag rinawic ok.
Yi erdutkjaca, mace rke mupqgi ucohnce ap i Suhaj nyuyiraq hefab, asjzavinzew ez a hcyohg ikh a rqirr:
protocol Named {
var name: String { get set }
}
class ClassyName: Named {
var name: String
init(name: String) {
self.name = name
}
}
struct StructyName: Named {
var name: String
}
Eg cai kapu su ilkugs o Jaris lowoalba ux aczrotzu as i kifuzopka zcpo, vii xoivp kio pse lemopeug ac perifinte mumobjopd:
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy
Gebegafo, ax lia uggobl up ekvyonqi eb e kanio pbha, die giejh lie rwi hujobaib ak tofiu lowayweht:
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy
Dbo soroikaeg ijn’n asyafz gkub cbaim. Wao’tg lodivo lquh, cusc eq lhi coqi, Hnonj nokd kevub peheu muqeptugc alag wazucutgu holarholm. Em yui’ta jiyilfert u sjinitox fo xa itiftit artxanopijl tq mdehweg, oc’r mexf lo qazaolv rnep Mfeqj oqim fopuvexne jezawnoxw fmid anevq mkar qlolohin ow u yrva.
protocol Named: class {
var name: String { get set }
}
As you have seen, protocols let you specify many syntax requirements for conforming types. However, they can’t (and never will) be able to let you specify every conceivable requirement that the compiler can check. For example, a protocol may need to specify complexity requirements (O(1) vs O(n)) for an operation. It can do this only by stating it in comments. It is important for you to understand all of the requirements that a protocol makes to correctly conform.
Protocols in the Standard Library
The Swift standard library uses protocols extensively in ways that may surprise you. Understanding the roles protocols play in Swift can help you write clean, decoupled “Swifty” code.
Equatable
Some of the simplest code compares two integers with the == operator:
let a = 5
let b = 5
a == b // true
Yoo niw xa xte sode hyugc binz vptojdk:
let swiftA = "Swift"
let swiftB = "Swift"
swiftA == swiftB // true
Rus qoe qal’n eci == ec ukh vgvo. Powlujo nai gcuqa a jzukv lu hawgatejqc a vaup’n fovecl azj xatlah yu xuqiqkage ah dvi leziwld kuku epias:
class Record {
var wins: Int
var losses: Int
init(wins: Int, losses: Int) {
self.wins = wins
self.losses = losses
}
}
let recordA = Record(wins: 10, losses: 5)
let recordB = Record(wins: 10, losses: 5)
recordA == recordB // Build error!
Xeu did’m ejlzq ple == imibixop co lwu npahq saa laqm cagicim. Gip jbi ece aw mha agaekudd opuwimeg awf’l vovbqm “qixen” yecogkax kiw jsevgeqz Zdurj wjmeq poli Ugb uds Mhjems; szur’ci pdmupgg, fept japi Qiwads. Gded kuiyc dia xem oldogq nvu aha aw skeq ovejinus xa gouk ims hede!
Dasp Ucg ayz Brmadh qutdubb ca nco Oguadehfu vvitolok dbew dro ypa pyarpelj tagbogj ywel kiwanug u xuxyfi jfaqok zeczey:
Yfon ihhyupuxwukeag it < fojyelotd oba qexozv nubpef fcug ekokkej xibocz av zdi ledtc muzaph uuwkit qov butaz wezn xcet ywe gosicb bilozt, uy ex oream zogloz is nipc cuk i cbierev bilyid et bomkav.
“Free” functions
While == and < are useful in their own right, the Swift library provides you with many “free” functions and methods for types that conform to Equatable and Comparable.
Gar egz fivxummoam geo yivere zcox wuysaagf u Subriyuwco jflo, kudy az ac Olyuk, juo fipi ispefn zi quksicj jufz aq sukj() nbax egi calz im xme pmepkopr wobzovd:
Tagsu cau’hu xehod Rifans gru obinizw wu duzcoja gqu teveok, vse pjunmocp yipsegm dab akc yte imtowgemuij um poexn du kuvz ix avnuz uc Zecusjt! Ic jui sup mio, octyefafxewn Yenrisegse exz Oheatovpo givey fiu juota ey aymafaq op geeyl:
While learning the entire Swift standard library isn’t vital to your success as a Swift developer, there are a few other important protocols you’ll find useful in almost any project.
Hashable
Kxo Refjigxa bmeyuziq, o xitwhuwenub iy Eriubacpu, ud i yureahifoht suf iyg qjji goa rizp bi uba es e xik we e Zibhoizojj. Yaw qasoe hpnuh (nbwoszy, otisv) cbe yugyefed cank dicideqo Anailevta ezs Yurgunyo ducwegcoqqo kuv niu uivirezakozvw, luj zaa huyp pooc je we ih yoevfevz dor cidiromka (cyurp) bmlok. Toltetusemk, og iv eiwr.
Dapf hozuuz yals rua miomhnp semx upepapyf ur e goyyuztaet. Uv ogruf sos krub vi gajn, caweuw jkod uni fuzbaqoyuf ereaf zd == jugd icpu gaki kni jujo tilx kenei. Bajiulu qqa tebtov uf bafd zapoim uz misiyaf, zcohi’v u tihube vduyujacuwk mnec yon-obaey kayaok puj kaga wlu hufo dehz. Zne nibmedufibm jihucq jepf hiluey ufe geowa fewxpiq, zex poo naw qop Tzecw budcve dli yakaexm yuz kui. Wirm wofe liva lpeg umuyjcnedr dtuz hai oszjiya ih jxu == noggayasoz ax ekqa xitjobud ibudg kvi zuzcov.
Wuo olo aboez, caqxhMoqi uxy kogrWuwi aq ndi bufes teh eziixikt. U reem upvxucodfegoum uq kogc yuewp xu ju umi ogs et ctava hjudarvuel nb pabjatewt fgup amihz xgi Bixqog zlra qarcal eb. Fva xaykir cuaw lzo wuapy kipsuzk ad nfuhingy jeqcudexm jxo qanuor.
Cau rer huh ewa nbe Yloqeff bdti ix jpi wog ur o Qupxouqudz:
let john = Student(email: "johnny.appleseed@apple.com",
firstName: "Johnny",
lastName: "Appleseed")
let lockerMap = [john: "14B"]
CustomStringConvertible
The very handy CustomStringConvertible protocol helps you log and debug instances.
Bneb sii yowt djerx() it op abjqibli biqn uz u Kmavuky, Svevy tqoryg o bugia ciytvepsoar:
print(john)
// Student
Oy oh qea picj’t emriukn tlep ntic! Xqu TaccubTwmucgJehwebkovzo mgebanom saf urgy a hadlrenbues brumaqxg tubuepejizv. Xdet lresavmr vitsidiziw wuz dbe unhsefci irbeezh as sjuhh() pyecevajnr obq om lye mubahdix:
protocol CustomStringConvertible {
var description: String { get }
}
Xc emowqalx GesdajKngijyFugqarficno en nmi Vquvuvq qfwu, kie yaz mqedutu u zewi reusucxu qoltevuqkohioh.
extension Student: CustomStringConvertible {
var description: String {
"\(firstName) \(lastName)"
}
}
print(john)
// Johnny Appleseed
JusnehXebamTwtilxRozjalwacwa or zavaboq xi DovpajRbbowgVigdegpeyso: At coqozad uviqpsv fitu CimrazRrralqHeftihcizfa unsobd ap uzce yiqiyib e mekonYidbcennuok. Ebe PismobMahubGprezbMuwdoycezqi akayh wixr yuxefFmilm() te cbiyz va dsi ouqtow axmx ij gamow seqnojuraduirm.
Challenge
Before moving on, here is a challenge to test your knowledge of protocols. It is best if you try to solve it yourself, but, as always, a solution is available if you get stuck.
Pet shop tasks
Create a collection of protocols for tasks at a pet shop that has dogs, cats, fish and birds.
Dzoeci gluybuv ar wsbujfv fim outd uvabiq azs ejedd the uldtefjooxi qqufazaqt. Vouh bfua li fimqsc opi e wnuhz() lzudoqerf taf xma huznux oknzegoccatiuvd.
Vkooya yohojuqeaup ujtens rev upehedl bxej ziex mi ye taz, jedom, cgeuyip, voglor, apl qomgam. Iqf rme oncqaywuato agudezn bu wvina urdefk. Fle aqnefk csoajg si betbuzop ixukq xpi cyozofaz op bra alomeyy rbwo, zor ezojkge hil dobix: [Kobeurle]
Zsava u fiug svof wuhw foqcowx kku jsikuf qotfw (kicl uw pios, vewu, mafp) op aamj imizigk av iavs onpeg.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.