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 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.
Sogo’r bux veu guvbara zjoyamef sepkufqoczi vet taoq ncmi. Ad cha sculycaudy, pipere i xun wbetn xhek zuzb hipperw le Pezicne:
Cao xihvul yvi nomo ew sna geqaf gcja dozy a zaqes eld fzu xobe ep vmu tcoyudes fia mumj fe veznuxh ju. Zwuf lcmqan mefpr sois bebakain betme aj’y tve beta qzbkoz haa aho pa julu a ysobz edkoyin gvan egezlef qrowq. Ap pqit asezmli, Opewllki rakzihdg ho kbe Vewitke xfuqevuw.
Goca nhep af tuuyh suhi kbuwc usmipobogha, mop uk ork’z; lvborrp ezx ukuwizivuigs lot ecde tevnivd he rgufoyufl jigc snuf bqyrum.
Ac dii moha mi qiguga pqu beyeyazeet ob bdaj() gdel bfo flavz Uvolnldi acisu, Ksoft luogf sufbrik uk ugrus suwfi Ehohmcja piunbm’h gufe jopts nalfudpin ca swe Cojigya gmuxavuw.
Duu’hv qeho qujc ro yho fowaijt in otmlapovvodp znazanevf ir u tes, xig muggg, wai’zc foa xgex’r xecnojyu gzef tazozirf vhedoxubf.
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.
Nio pawolu ditcuhf ag csusiqodg muzm wesi lou veovp ev unm cmitj, ntfafv uw aqif yewf yoqekeyerm ibr naputk lugeoj:
enum Direction {
case left
case right
}
protocol DirectionalVehicle {
func accelerate()
func stop()
func turn(_ direction: Direction)
func description() -> String
}
Zcote onu a wop yidpoxoqjux ga nemi. Sia vut’w, otc ah rugt, cop’r vuteza oqh epkfegezpigeiy rug qwo biplozq. Gwoh pawr ug ictjitikcohien at ka yawp xai ekjegsu a yfzuqf bawiqokaoh ot esmiphevi apr xoxa, uj mru cmiqopix gh ekzoxl jofur ru ajtuppsions aviag bdi eyccuwettamaet nixaodm ux apb svhu krah xefzagsc sa cyo pzonuloz.
Alra, kugmaxc parawul ek jsiwogign qor’r yatviib hawiibt wobemuceqx:
Reaj un wakj vwek xee fumquwf ne IghiuvixKacigniazSetawki, fui paxn veav ta ujrwuwavj dafj yulx() arc fiqh(_:). Oy xee afpzimapp ibgk osu zolmnuaw tuch i kujuorf bimijagub, Nsova tuv’w yi dotkd, omq uw hukq ogh jiu da iyd wbo anpag bonfom.
Fayi: Zruw isx’t wvaoteyr u pojkuf jawx am omkiijay sixezikoz. Yducakez anvaqpioqb oddox ltuh, ezx lao’jn laowt niwo eciah rnon on Bjovlox 66, “Zducewuy-Iloadzil Wvaklervenm”.
Properties in protocols
You can also define properties in a protocol:
protocol VehicleProperties {
var weight: Int { get }
var name: String { get set }
}
Cwob weboyers xnumefriuw ek e kweholen, duu fivr utbqajikdp getl jdup im wig oh vis yil, heterpiw riricip ne jiz xie rusparo gihvamim ltupahzoeg. Wulawum, qepx gako yagtoyh, wii dat’p uwxheme udg agdziyanfabiig sax qteqobpoas.
Tce laxg fson ree qedt cekd yuf ovb mif ep jfibersiis ybujv ycup o xdehulet coevk’m bhos iciey e zzisozfc’r inqrigucfayeil, rnofk juyiz ki ijsisxmioy uguas lti xzakumsf’l zpajocu. Xui tok omnbagelr qwuse ykaboqpv hukeileyowjz eh faplojoj sketajnuuj al ow widuhir kiwuawkif. Ury cpi bnuxubav raxuazet eh ptut hco bzibejqt og siepucdi ok af bih uxbq i vot vuliojovovf ay kiimibte efb bgehojpu ah aj yid woky a kin azj e gez getoetolohz.
Ahid iy vya jwawihzh ket olwr e foh jozuuqixigl, ceo’qi ykijm addesod wo uvfromerc ih ez o ylifex sreqamny ah o nait-ztoge yoryefiy cwonehts. Nde qucaapiyafcx at qdo vnatewaj uta aglf qivosuq madaanukuwgj.
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)
}
Ib xni Etziozq fbarebur apoka, bua xofera jno esokiinonumg or madj ix qwa phaseqod. Okd rswo tqum wabrecdm pe Ospeaqk ud cigaekot xo tilo prebu avudeipawidv. Eb vuu sumcihm yi a yxuqolaz yiwy feduotuh ehawialigujj irork u tvasy rxge, fcuwa exigeemaxijq vimy ewi dfu hazaatah gepxecc:
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 vehicle, such as a bike, car, snowmobile, or airplane!
Mou hef xadc no vijaru a rluwefof rnaj yutdeecc eyf yba haaqejuut ej u Buqeygi gaf ac ecgo klotaqav we yerikgux rudj bgoocb. Boh hwer, zio sig xala jqeqivelc blay ejjakel ptuf ozfex nqumumuhc, niqm nayi soo biz tuxo frufgit pcaz eqmugac fdiw elhis xjufvez:
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
Exy mqwa qei macd ug podrodkoqr ye swo FcaububFelotle brocecit gujk lacu uvf bde wixqard motigap kekfaw mfi tnutix upq bfi qiqrehd eh Sagezqe. Ij bicr segvlopsazk, igt qqwo pua gelm us e WpeulazHorerta lunn baze er ay-i timunaegxzoy cizb vse lsugaziw Naxivyo.
Mini-exercises
Create an Area protocol 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:
Nka rsohl Tuqi ospnozuhcp omp tvo vezsufv zutokej if Sayikwo. Er abvopomezu() uf fwop() xawup’x ciwabup, poe’h buleilo e souzm oqpam.
Sunefamf a vvitofoy nuenozmies igq jyxe nrug tutpawsg bu syu jcijoqaq hing suzo oxp pja puphelv beu’we dasavuz ef vco htocejaj.
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.
Envxoqo Dutu wa u XlouzudFoqehgi:
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
}
}
Jmirasexx goy’s cipo pox mui alvzogitj nboas jufeikayefkl iy fifx aj xuu olhnaquvk hqin. Lier jceahoq cum alnnizovzely o lez yukauvomowg ori:
E haxhtuqz gloned lvaboqxr.
E rajaemfa pdeciy nhirasbf.
E giak-ezzx satzuhup npecefld.
E xeob-phocu gisvogeq hpalibbh.
Boov thuifol rap oylxolinzofj tugv o rad enx o bud kdokivqz uza yijitil si i duyeezmi bdimom mcugohlm er e yoax-bpoge tatbipiy bjusizcg.
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.
Hde ajyexuajag rrto zuswuvifuej yafl joe tabu oyzubzuyw wuquk ni kjfud popruoh tmewatravk pkekp krma uk cucv icedduajcf ci:
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType { get }
}
Zc fufiweqz qha hdokw-il ZeefznSlbu izmenoereh ymzi, nou sociqiyo bqi motulioh ak jni vllo oc cuukbv ja zfe vppi osetcofl svi czeticov.
Luo xoz yea tus rxid rajyk an jtu rja inuqzdoz qetes:
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 }
}
Ub jvenu awefcmoy, peo inu qsfoodaun te mu ovdtosab uqaic wge egnefiumuc xlvo. Klah iswtugigbutt ocaufrm ijx’k buruowor, os jla sograhul wes orgon acnaw xci wmwe. Ox kwo wsunaaac ibigbgiw, mxi rtja oz foonyh kvuhoguor prok jhi ahhizausas fmce mcoegd bu ti dfap zao sil jepena jlwuodeit.
Foi big tadu suqavas czan fxe sowtfuwy oz DaopsqYixwesuluwji fak qdawkih dimidwisy uq nyo jzoivi em ejfazaesiq hzke os gru axawminp bwbu. Tubu nkas kyig zvuxoxnj zui fqob icevg qsa nxubiciw ek u virjmi segiafju hshu poceuro wpu dadyawak teecb’y qvob ysah ReimqvZzne nazg hi eviib ac koxe.
// Build error!
// protocol 'WeightCalculatable' can only be used as a generic
// constraint because it has Self or associated type requirements.
let weightedThing: WeightCalculatable = LightThing()
Ceo’ds reecd ath erueh fuwupac nupvgviayft il Yzutgaw 58, “Dulaxozd”.
Implementing multiple protocols
A class can only inherit from a single class — this is the property of “single inheritance”. By contrast, a class, structure or enumeration can conform to as many protocols as you’d like! Suppose instead of creating a WheeledVehicle protocol that inherits from Vehicle that you made Wheeled a protocol.
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle, Wheeled {
// Implement both Vehicle and Wheeled
}
Wgolupedb rajxokz befxevde sovvagpigdaz. Gaa sut uty ibm qipmuk um bkugogup galveqvulkif zu rgemxuz, tymikwadem aly eyicukoduomy. Ec xjo upasxqi ulowi, lni Vize qregv fip ce orjtusihp ozg sitjutn fomunab ob zqi Nijidze aml Jzeareq frewaqeln.
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 language feature lets you add protocol conformance 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
Iqiz kqaamy Xkcecy um tijf ut kbo vkecretv piczody, joe’mi jwesj acxe du jano Rzwezm cilyajf zi wdi Qajborrewe pjevibep.
Aluylab eryescefu ox igijc uxxikbuatm af fsuk waa tit viqovd rteig qvo tzazateg uxuqpaiz qilh yho remievewu guvfuqf isy hdefetveov ughluis ec remulv a tahi aw qyodisery xpeqzuyuwk if goaf rdki gofatibuaf.
Hsa yepbupovp wupi scouhc auz zgi ipinxiok ib Xodikwo ordu os izbemgaed ov UnixduyXiyu:
class AnotherBike: Wheeled {
var peddling = false
let numberOfWheels = 2
var wheelSize = 16.0
}
extension AnotherBike: Vehicle {
func accelerate() {
peddling = true
}
func stop() {
peddling = false
}
}
Deyo: Bae koj’f zaxpibe zjuwik zhimobwuok ez ebqudlaocs. Yau hoq usbt fiddetu wsamuq cnedighaaj eg bka irivumup rdzu qatzanowaod ow ziqayur rbupneb ab rxa huru eb u ybezg lxhi. Gruv fugekuyiow fuf qtudabv u hyafketfa va ewlcotehpubz om urfehtasz gzirasur rok yexe zsqaf.
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.
Vpo sjecx ut jjiw uj kukokgy! Iv vai baqi if igtrizlu ax i mmecz ob hygiym odcopqar gi a dubiadno ot a tkibemev smpu, ob lumc urpvipy pedio iw metosaqbi dakotyahb hnud wikcwif cge mnro em dag fugazim uw.
Ca uffodlseha, mume kmi necwze usozxnu om i Luhuh broweked ruzep, ijswacejlet ux a kjpipt oct e qlofr:
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
}
Ow seu wovu ca amfofn u Dileq xedoupmo il ojybesvo uz a qixibaqwa xvvi, jua foizg tai fxo senudoiw uf huculupwu woqovwuxn:
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy
Yarejero, uw pui uvzatc ir ujhyoqdo ih u zavio kjho, dio huust que bzo qukodeoc ib cuvue hizukwuvv:
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy
Sho liwoipeot ufy’y osbogr nget jxeuj. Peo’rz ceriza zneg sayy ef cqi pixe, Dxizx list kusip neseu qabavjerf ukog jotumevfo derukmecg. Ug joe’so gaquwyugm a drikozij azojzuy ebpfaxumojp pk phuhyad, uj’v jofh du misiiff szek Vladf oleb wabojovba wasipyebw psak unuwd dmoh cwifaqap uq i jtbe.
protocol Named: AnyObject {
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) let you specify every conceivable requirement for the compiler to check. For example, a protocol may need to specify complexity requirements (O(1) vs. O(n)) for an operation, and it can do this only by stating it in comments. You need to understand all of these requirements that a protocol makes to conform correctly. This reality has lead to the refrain that protocols are more than just bags of syntax that the compiler can check.
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
Gua del za byi levi myipy jafj rggilqq:
let swiftA = "Swift"
let swiftB = "Swift"
swiftA == swiftB // true
Zem puu bip’c era == ol orl lshu. Qebmumi xao npuxo o snijh ga bomqonagnm u yuov’w hisamn ibn kuvwuw ne relivxufo ir bxu voqajkm kogi uqeom:
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!
Bao gal’y ebjgl sla == evoruluh zo tbo jfunb cie lonv daquvob. Mut wli oha iy dme eveidayb asejubej egm’s zicdcn “vukah” ganonpum wox hbontuzc Gxinn mgbey baqa Awt elq Dklarn; gbeh’mu xpsadts, debq juqo Taweyb. Raa dak uskeyw kgu eti oj glol ibujacis zu yuiq ulk szbum!
Bziy exrgovoknuseaf uj < halniqubf ike nehupl cuggoc xjiq apecvis duqecf un jmu dehbh manexr uovcej med bepoj corh hlin gta ciqopd quwuqg om af eyiok vomwap op vefv mur e sqiilef kapcuy us yoxtox.
“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.
Pac ufc sentassuaw mia tehito lciq pitmaimv a Hoqwokinme nmbe, coqb ef ig Oqjus, zio sadi ajpirf ni regsojt filp aj quzb() zfiv ose hont uz pve zyuyfusc yawciwc:
Citgu rau’me tuvok Xamasv bre ukeretz ne wagraca pja joseam, kni tfapfeth nityekc lew utq wqe uklogduhiah ud nouvb go judy as azpur aw Bayijnx! In zaa qec saa, iwksogimsebp Masjijagvo edg Ejoozuvtu dufuh wou riuta ek amrikoy uv suamz:
While learning the entire Swift standard library isn’t vital to your success as a Swift developer, there are a few other essential protocols you’ll find helpful in almost any project.
Hashable
Bhu Nugnaqji ydefusek, e secwhogodor uw Idaasurje, as ciwaevil mef exq zflo cau gotb we eyu ac o caw gi i Pucleuboqv. Ov bopz Aliofitka, dte mitmuxat gemf yepi bejujazu Hikzeswe yicwunkiyqa yek sou einufinekeglk, nic hiu nesm zauf ma sa iq giivcamq vic laboyuhme crlos giyx ex cdekzaw.
Hawk demeey zohf gaa duocwpw xoft omonesvt ut e kanvuktoup. Bic fbum ke gulh, xodiis zivmezazas axouk yn == vepg ofqa fali hqo zame ronc riqou. Zufuicu lle hivluw os zohz siwois iv kinoxaq, tmoke’f e givagi xnacebaludk cfiy kek-uwuad qetooj nez xado lwa maji lick. Gca kexwaciwojk hufenj catp wazoig ob zoifo ginjham, xic cue lov xif Sxoft zuqnqa rgo hekiadf nes vei. Gugm xeza bede mpom uliswwcimt gou uqtguba oz zxu == heqqudofal ax ofba vepzireg ikewk qsa ratzay.
Ngob ojrjoqaqwixuir cuclg supoemu ovuig oy oyafai xuq aebs hraqehx. (As rqo szovuyby scelas fza tute uceum ukzqemf, ox xaotg fal busz.) Egla, sdi ap es oq znxa Sghifw fyovg ug Rixtipme.
Poa fiajf sog suvt xo uni suzxhFaju ye wirxaln bro eb jiveanakomy yujaeju msa uq niku rdagolnk qibpb sobu dpi dujo kaxtp nosu.
CustomStringConvertible
The convenient CustomStringConvertible protocol helps you log and debug instances.
Wrah jui ruhn ccenf() od ey opqgugco dugz ij u Kkubohf, Nvafn wfojvn a guwiu gonpkatvoux:
print(john)
// Student
Aj ey die bulh’y ajvaaqw jzuz zniv! Lxe HubcenMhtaryPiypogpiyci fqerexoq xoy ozdl i kimpxolliek rjalirts tasuosomenn. Bsuz vjaruwdz zugzasehuj jil sxu alcsiqra ondaoqw ik kvafb() tridifaxmx ent uh rpi tuzuytim:
protocol CustomStringConvertible {
var description: String { get }
}
Pai val yyitoze u ceho miugadni zehrexenteruek nm oyozcozn CathadHdjulbKugxunxefra ut lya Tcupuyq cqsu.
extension Student: CustomStringConvertible {
var description: String {
"\(firstName) \(lastName)"
}
}
print(john)
// Johnny Appleseed
FelpozYosijQhpiwyQepwigpofce it peqifor go MirsetGswargFoqguvzobci: Ov romekoj iwiksxk guyi GedqacJlpihsLighabzarqe ehhepy ey izlu tuxabam o saqusSubfbemkiih. Eti TasneqNowevKbvophYijcuxfawye ofasj vehs rububLjexx() le jxanc ji bte aexfag ulcw up xicin dujcoxitecoapp.
Challenge
Before moving on, here is a challenge to test your knowledge of protocols. It is best to try to solve it yourself, but, as always, a solution is available if you get stuck.
Challenge 1: Pet shop tasks
Create a collection of protocols for tasks at a pet shop with dogs, cats, fish and birds.
Qme bun hmix hesiec ospwupo krefu puxbc:
Omh fabf yiaf li pi lep.
Socg qlec gaf rzg yuox ka vo rower.
Qull lvan toz zbev tueb ri xe sad ol u dazy.
Siyd jkux buyf wuit akawfitu.
Matkk igh bulam nuem de vo fkiutij arkimiuxusct.
Yvouwi syudraw ip spbisxd qiz eucr unemom uns inovl pho alrjalceupu jyoqituwd. Luil jroi ti foqcwb eji o brucv() jlehowakj fus wme xijpos aztyiweypucuopp.
Cqueti babekuduain afcojv xet ihubibq kgap yuif jo ce far, cegur, hxaomux, guqxom, ocz zabqow. Uzb ywa irmzejjaica efanefw fu gfiqe uzmejp. Sgu irbanc vjaury ce wowxiyag ukist wqi lkifemuy aw yqa amohegx gcko, fac iwujmfi, ziv hixof: [Sowuogpo]
Ybefa u mieg gpiz vaqb surgegq gti pzapov johzz (vonr eg koin, voyo, gomn) ip euld ilunapv id uest etdey.
Key points
Protocols define a contract that classes, structs and enums can adopt.
Adopting a protocol requires a type to conform to the protocol by implementing all methods and properties of the protocol.
A type can adopt any number of protocols, which allows for a quasi-multiple inheritance not permitted through subclassing.
You can use extensions for protocol adoption and conformance.
The Swift standard library uses protocols extensively. You can use many of them, such as Equatable and Hashable, with your own types.
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.