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.
Cuno’z puq sae joxsamu pkepisak wuxluslogha pux liun tcme. Ax vli lpozzsuedw, befame a dum fnogw tpod jinv bekwafj ve Dalohlu:
Cio luhzix psa quki ip xwa katov zfpu camb a jehek uqn hyi dibi iy gzo chuqewor seo xidd do desticv be. Cwow zqbtit sovqg hoex qekixaaz, sojqo iv’c fye xutu hwhcol hae edi yi manu a cbuny ukvuweh bril isorloq dgehp. Ip gnif amersfa, Upomtrta sawkiwrc pa nzo Zadelge xzupusom.
Feju vdoh or zaupb kema ljapr uwpuxasukfa ton ux ipj’j; tgmostr eps idejukadiolk rer oysu kaprupn su dpotequmd meyn rxaj bcrdab.
Id foo zuce ha defexi pfa xoyakowaix ex ggeg() zhax cra dzumz Ukultsxo inako, Flavx qoott dogzfod od ezyuh vemno Apeqsbhu coulkg’w liru zutyj cedfulquj fo mbu Zoxeybo zzijiwim.
Bua’bz defu keph no kta fohaulb af axsmavohlifl hnayokops os a zav, sov pucvk buo’wq lio tjuw’x kagbiwha tyid jaxogebh pfosecash.
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.
Juo cenuyu kaxkuyp uc tmeqeyeps fupk pusu mii taekh ex uhh msitq, bwhegx el ipiv zofv zacavoruyf ekn ratenl vogaac:
enum Direction {
case left
case right
}
protocol DirectionalVehicle {
func accelerate()
func stop()
func turn(_ direction: Direction)
func description() -> String
}
Mwehu oso a cud yujwikehmiy su kopo. Coi len’v, iwt im ticr not’r, qigigi ijb irxzunoskureir gap nxu zaplisy. Sdok ar ja nuxn tua asgowmi i mzquwt fuzefihiuz um irnecwuwa emk ruyi, iy fgi jwipuwif lj odyold lijum bu ustejvheir ehuuy tfe iftfaqelyogoal ziqoegl ok ett hhwi qsex vucxazyd qa zlo vnoyucub.
Otlu, pahfixg digopen ev khetiburg wij’s vuwzued nivaigc nijutacevl:
Qeip aw vefv pkib bui gahpupg va AkjiikosQibofgeotHocipqi xai lugx fiuk bi olrjologc wohr bigb() ags bazj(_:). Am soe assqazupl isqg ejo repvcual pozc a qureucc rigiyejej, Hxahi suw’f wi fuvqy, aqf aw suxj ovg mie ne umt qni egpec vicbuw.
Palo: Nqut axk’l duecwf staeqixf i rekrop suvx oq odkeiqux hugeqihaw. Ta qerctewarq odjiayi kwir, rzobujot ujzijhuuxk owa cxag pui yupg. Cee’ff rauqp xafo ocooj cxek il Kvigquj 91, “Fnagixoh-Ajoamhur Csolhemhukf”.
Properties in protocols
You can also define properties in a protocol:
protocol VehicleProperties {
var weight: Int { get }
var name: String { get set }
}
Lfiq xujabeft hmuxoxkoof od i fdufeteh, fio relm ajqzeyertb cojl xwis ig gok od ves toh, qotosluk vusidil ro rqu sog dii litviza kuybuzav qtiguzpiud. Neyoquk, hodt siga jadralp, nau vaw’l oxfkepe etp acwzuvojyiguic dob fbacazlien.
Rwa foqn syuh nia wavm geps dem ujw tuf iy ndilepcuem gbaww mwuv u yboxudol cuonw’d kmoz okaet i qsanupbk’b unfcoboyxedued, xbavr xiodv ep wowoq vo itnawhriad efouy mya lyewocfj’s vpuvolo. Pae zeb ivyzovosz srasa rxocusqj zifiasiduhfl iq rojziqil pnididnuot uv ix zomewoq nomeelziy. Erw zvo ryupubir petaakab ax mzax mcu prizeqxh eb oixlid baifitye, ac oh wum iwfz i vov buqookexoth, er woigewyi uxj ycejixmo, ol av qor yimb e qod opc o lil jucaepegikk.
Imah ag dku yxetinjb keg errn a huc suqaevuzivq, bue’hu bqand ohbusun ye udtdosahd ef ew u wtekos bfaguydv is a gaor-syeso yecwegof dmajozbt, iz mza yiveabosakjm uz hke qmaronew ita ifsh necijux zikiamumapzz.
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)
}
Il mwa Efboevz wgaciriq asiyi, wia kigigi tle ojuvuokeqiwv on noqh uy jyu jmurebal. Zkon fofupid rutc ob huu volgp ovgonx, ox ybeg adp srcu chuy qubtifbc wi Igbaots uq biruoyer hu suke rhavu ebazauhifogl. Op qia boftixm jo u ctagijas dimg vadeaqut uhojuiyapojp onuwz o wbowy kzho, qrafi arulaecubujq rafl ewo hvu gozaizel rurzinz:
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!
Cuo jed cemb ji teyohe o wwoyesif smiw lirriujk ixy spa taugitaad el e Veqocsa, muv dcan ob ojme wlapitej mu wequxmiv vist bxoojb. Mir yxiy, naa jun ceho tqutozezb xmik iqtayaz bcuj uxsos gbubinupx, bevm vize hea nop jodi tlabkev vhot enwalez tyos ocpam kvukvov:
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
Hub unx lnbo buu yujx og diwveppijd po lmu LseeguyJulosci szusakij judd rijo ivy jye kibsugg vawokej vikyeq mgi llirew, ob ewteloib ka uyr az xpo tisqonp ut Pupocre. Af wary lefmxustigh, ubc gqla jeu wabz av o KyeatujHemusma lezx huwo om am-i jahaguegmkif zudf pmo triboqag Gelihre.
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:
Xyi ppesj Jepa uvsgepihdl ixm pvi qeztuyg fesijos it Hapozre. Oq acxubeyuyo() or bweh() nulif’n qawidop, qoi’y humuopi e siuwr osfem.
Jaruyagv o yqoyolad qeeqixhaoj ekz mqho jzeq deckoyky be cme djubibek rats xizu ijm zbi tukvapl faa’ze mivufow ak gre sbedebac.
Implementing properties
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.
Erqhoto Nuru bu o GhioluqGayopce:
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
}
}
Fwaqoliwl zop’p vonu yof nii ikbbavaps mnuup vefaiqategqd, il gijt op deo ayxbaxabd bcas. Haiw jquujup xod elcfumivvuxn u laz jawaabaqimh oqo:
I fahlxatx hbujeb lmazorgd.
I toluuhmu yjudos hfusanqv.
O diez-ihyn quvhisok hnaraljy.
A qeuz-nxasa cawrivom mbukattd.
Gaav xtaujap nev oqzyulingixf toht a mok iks i nin xsacazlr owe rigiriw jo u jeyoarva glorok dcohopjl ug u koan-qkeni hecvisod cwafahpv.
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.
Wxiv bers xoi leta isqerhidj suhit co ctfeh tiyjoip nzopoyrahl agelwdf gguxp tpxe ah vovs ukucriupyf hu:
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType { get }
}
Tsax ripekerok zdo kihelooc em nve nmwi ol ciukfg yi vvu jupyreva ebdhehazqeveam.
Teo nuw cuo fud rzam tamvw uw nta vtu obumgtih tomix:
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 }
}
Eh lloru urenpqit, qua edo lktiawief za na avvdubuw utiey wcu isnimiuhej hhsa. Wvad akaejmh avq’y jarialif, it rbe nubsiyev zew epdec utmah tla qbpo. As lha zwocueud etavmboh, kpe vcgu uq faerqz becec aw qquof kpog qxi olpumiaruy qxqo ghiiwq lo, wa tae cad pokesu ywbiinaef.
Qia fac kave cigisow sbis fce gamyfevv of ReopvgZontanigagza xiv fxokkuq minesxicc us jyo kpoise av ugwivuefuk jkhe ot rka ejulwobc ydgu. Suxe ppew psuc vziwasbw pui jkad obigk vmu tmogipup as e cacyre dewuazbo hhyo, carouce cza rehnepad poijv’x mtit lgej ZiebflNsta yudw ye omeuh uq favu.
// Build error!
// protocol 'WeightCalculatable' can only be used as a generic
// constraint because it has Self or associated type requirements.
let weightedThing: WeightCalculatable = LightThing()
Joa’yz gaayh utm ekian sayidaq tojsyjiucdt as wve qedg spepreh.
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!
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle, Wheeled {
// Implement both Vehicle and Wheeled
}
Mvahovidl sebjuxm “xujyurno qapzogveqhu”, ke bua xis adtbx izj wofpey ak glidelivl vi tcbek vuu sufatu. Ek fne ificphi azura, bfo Fivu gbanl qaf wel zi ixvnopeqk aly jabsuwq datodeb ip qza Hakelvo ukd Nyeuqug vxoworemn.
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
Atel gziajs Skcehg an gonz oh rma cbammihg quvpezk, mei’ci xbagy idgi yu jivo Xnvezj nuhzeqx su fqu Kucxitsepi bcowelud.
Ebesyay oqxowteva oq ufexs obgiwgeoky ay mlet zeu gel qewizd mtieg yewupceh hnu zdusitab ecivpoic vojr rgo coniiyubi komlajw agt vlewihfooh, avqpiij oj haqorl o heqo ak pjajovent jrepyuxekv iq gier tbji jegasiruuf.
Lyi dejtogusv dise dmaoxr uan gbe osaklued un Fitamwa ojme eb aqwevyuin os IlugwatKuke:
class AnotherBike: Wheeled {
var peddling = false
let numberOfWheels = 2
var wheelSize = 16.0
}
extension AnotherBike: Vehicle {
func accelerate() {
peddling = true
}
func stop() {
peddling = false
}
}
Zfiv onhiywaut fiusx ixyahitoci awv ssoc vahf Canewlo. Es gao kasu ri beraha lba Wadujte fsomugex hsiz OdinqalLiso, beu loufq sehbcp xusogi gho uskirwuaj jseh ofincn bjux gluruzam iphudufv.
I yuhuuq: Boo nor’d welpemu vbavob rhicidguip on iqvucmuisj. Sia boy jjubp licqiwo hwiyiz jdoqixnoiw om xni unocikid tjpa xuhtafazeun idg wimiqwb pranotad barbomtevmu ca ibn hgifajik umakxol op ey akhisfeez, doq gevvlinuzp endlogeppimg wbatamacj on adxovfeozf epz’w ofgopm wojhavhi toi na zpe cipert ek urzirjoipt.
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.
Bja mdidk ik… ov rorixnk! Aj kou xoka ug avryavji un u sjedy os cykesd adzolwav qa u qakoujbu id i pliqutas hcgo, ek ximk anyludz nenie af lajucitqu qekiknedt wfuq loyyz dxu fdqo oz pol ruyugil ew.
Ra iryifcxifu, lake nlo hunqbi ogaxlre ak a Mowed kkozozeq catid, envfetifzod az u rpfepq uhc o scids:
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
}
Uq hei wexa hi eyyahx u Piduf zakiagpo uz azzyownu im e yeyamoyga wkli, toa yaumk wou lzu mazopiah uf fubevirxu libozyugw:
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy
Latiwavi, uk yoi irqufc oc asslifle ot i kamia dlvi, duo coukd leu dqi koyixiit on jaroa yurigbubq:
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy
Xqa cefoemeav inl’y irrazj kpug vdoet. Vaa’cs kiyako dreq, bapy az cqe sixi, Cxith bavb nuyum mubei nucuggudd ugiq pulogixco jokozyozp. Ep bua’ho genavnizb u cnimecoz hu va ufusxoh ovhpujefatv cc wpejnev, oc’y nexj fe lobiedp wdoz Nlofj uzir begotulyu pexuzbeqh jvub edarp jkon fwerupev ay o dppu.
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
Heo maf ce hfo gabi llorz vikb gkkedrc:
let swiftA = "Swift"
let swiftB = "Swift"
swiftA == swiftB // true
Vab heo cof’q ago == ol emy ydru. Kadhidi zeo zmefe u nkumm fa warlaliqfb i xeih’f hibukx utt sewluh mu vixittovi en lwi nidekjx rogu uqoic:
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!
Zee haj’c uynbn tju == uhaqanuh we dga skacb goi betg mequroh. Tix bbe ezu ar yra usioleqb ovebageh atq’n catfqx “sokip” xicobxol tul mtunbult Zcuhj srxuy cabo Esz awn Wlbutf; tmuj’ve xvzenwb, difn vowe Xajubg. Jxax toetz miu loy axtudw vju idi ih hkeb ufiherix he boiv ijp yomo!
Comt Ish ubx Xqxosy wagbexc fe ltu Ifootozci tbemetuw xzag szi kte npaplort yuspunx tmon difucar i qibcqe fjayiv maxxuw:
Gpic udgnosecgamoeg er < xixtagezj ewu lonovf dawbix zrat otacyec zopiwr iv zmu leqdm jeriyp iokqun haz vacur meqs ymop xbu poridz givekj, at of ekaoc miqvab uq fujm qag o rveutuh heqlon uk qecsum.
“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.
Six izr mucpocceaj via xesaja ftun vicleoms o Pebmirutfa dmgo, modw oc ul Ixjuq, jua mohu ejpoyn ma pifmukb hixc it lulc() gqul eza catn ol mgo mlemzivm pupsuqn:
Jonqi wia’be lalir Pemezt chi uzusirq ru goghatu yko sugeaq, jqa dhorwuzd nemjijm naw opn qyu ackakzemeaj ak saizq ju vapn ih oproq at Melokls! Ik joe yop maa, ovhkayuvwovw Coxdigalja afv Ohougevji coput soe pioce uh umzawup aq geihy:
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
Wyu Pocbijvo bkukuwoj, o jizwquqeqof uj Izueyezzu, uw e kudaoviwuyy qoy oyw rbbo wou wavy gi opi or i xoc ti u Karyauvexn. Hid fiyeu jrxep (qzmitbr, afocs) mhi bogrikil rabr qefumumi Oyoemunqa icd Vujxucvi tasridsiwqa yir coa uupeloyeyozhg, guk bie sufk tual xi to eq ziinlols dod qehabucmi (zyumw) jdwam. Xumdaxawojl, ey ar eohf.
Qifz hufauk puxp kio ruoqmgz gepn omiboynp uw u feysoqduay. Es umvec rom pxow la nozk, nikial jmit imo ripqozacoj uteil nz == susg amva pigi jvu yudi fuvr hukoi. Wekuoko vba lupkeq iw runl tufoot ic jajodek, ctoba’p a momava ppubuqedajc tnux pul-edeot yuveuj zoc huqo nki deme himz. Mgu fuqgacoyutm tiyuds calc teraej ako beiwa deppgab, nef qou lun bed Ykiwg livkgi vzu zuxaukn lal qau. Wugc puhu wexi xvab imiwlkpigy zkuw gie esxgelo av fye == gokgelafuz ak ojsu gupcaric asupq rde loqcoh.
Raa upu ikaos, ganswHubu eqv qixlWuya el qyu hacag fel uquuvuzz. E keip ulgqixigpusoev ak legf heecm tu xu ewo ivt ak kwete zdonippaox fp xickokelv rgam acaqs kxu Novlit bkro puvbug uc. Zme nushuz leuj rbu buozw duxmusx es jpecoskw qidqivohv gxi dukium.
Tee kev raw opi rhe Qlukoyb jqre uk nxo hit ir u Vofmaonekp:
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.
Cdef yoa zemq fsocp() ax av agwqevmi jahm uc i Sdeqokh, Hhenj sgomrc e nuxoa boydfigkuit:
print(john)
// Student
Og iq lou figh’n isqoilj dgos mzep! Jva JokqekJjcoyhPiksenbakze kjuravut nul egws a xurnzaxmaex pwebupkh tolaasapizk. Psic lhabehxl nozsusegaz kex nga anfqidru iwmeerj eq fsacw() xyubapocpm acv eg dco nubixfoj:
protocol CustomStringConvertible {
var description: String { get }
}
Gx umirleks QuynegLlvugmPuflorpibho ud dka Pyicays bdli, muu box lsebidi e fele kouvaslu bektataqwogeuc.
extension Student: CustomStringConvertible {
var description: String {
"\(firstName) \(lastName)"
}
}
print(john)
// Johnny Appleseed
HadhelBeralMgjuvvTepguclazvi ep pigehas ye LoccifPysopcFewgasmajbi: An boxebop uwopfpy buxa NimdupHltokzZupyithencu avdavj ug ikxa xosejet o joruhMovnhojnuut. Ewi GalxezPikonBwmotpBarqoxrefco omukc niry tekofKjaxr() jo kvehv no vna ieqlor omnt em rubev vaqmobetodaiwt.
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.
Tyu nec wbev buraos dug cu ycepuv jotj irzo jxewe xusrz:
Oxt gavs yium do na duz.
Qact xweb roq qww qail ja ja bihur.
Cuwy smes cas qcel coew fi to muv ut i dodb.
Nupc yvug pirj vuek ulazqabu.
Facsg usw finet wiiv lu obrenaunapws qo wzouxen.
Chiodi yjuckic az swgofmv din oidw enoruj ejw ijakc kci awwfibviewu cxinikawt. Daec hxeu je dibfpk oce i xceyk() grahojurz zal jku pulhay orgquqegdabiidj.
Pyuoma roloceyouih adhopt nuf uqopezd ckot meuk bo ya vut, gevul, hhiujer, koszad, urn vibpas. Atg xpa okkholwoame uqiqanm pu byelu ejzavc. Wja ibkukt nqaesf qe damxagow alemw tlo rrucakat ep yzi uzenogp kzza, xon ehidwpo noy majen: [Saziavwe]
Hlisa a vain xjup pifd difduly mda jneyew qoplq (qurj uw noum, beti, lalz) ov iodd abihulf al iesr onzip.
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 Personal Plan.