You’ve learned about three named types in this book: structures, classes and enumerations. There is another very special one: the protocol.
Unlike the other named types, protocols don’t define anything you instantiate directly. Instead, they define an interface or contract that actual concrete types conform to. With a protocol, you define a common set of properties and behaviors that different concrete types can implement. To help you remember that they are different, protocols are often referred to as abstract types.
You’ve been using protocols behind the scenes since 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. Start with this definition for a Vehicle:
protocol Vehicle {
/// Return a description of the state of the vehicle.
func describe() -> String
// more to come...
}
Following the keyword, protocol is its name, followed by curly braces with the requirements inside. There is only one method requirement, describe(), that returns a description. The big difference you’ll notice is that the protocol doesn’t contain any implementation.
That means you can’t instantiate a Vehicle directly:
Delete that line and continue building the Vehicle abstraction. Add the following to the protocol body:
/// Increases speed until it reaches its maximum speed.
mutating func accelerate()
/// Stop moving. Reducing the speed to zero miles per hour.
mutating func stop()
You mark these methods mutating because when they are implemented, they need to change the instance’s state. You can also add a couple of property requirements:
/// The speed of the vehicle in miles per hour.
var speed: Double { get set }
/// The maximum speed attainable by this Vehicle type.
static var maxSpeed: Double { get }
When defining properties in a protocol, you must explicitly mark them as get or get set, similar to how you declare computed properties. However, much like methods, you don’t include any implementation for properties.
The fact that you must mark get and set on properties shows that a protocol doesn’t know about a property’s implementation, which makes no assumption about the property’s storage. You can implement these property requirements as computed properties or as regular variables. The protocol requires that the property be readable if it has only a get requirement or readable and writable if it has both a get and a set requirement.
The maxSpeed property is marked static to indicate that it applies to all instances of the conforming type.
In short, you use protocols to describe the requirements of a type. What you’ve defined here is the abstract idea of a vehicle.
Protocol Adoption
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.
Laci’s vid gea yozkije nqodogox nahhihxewxi wes lien lkha. Ob hwu sbanyhaekr, nuticu a cup mwebd tmuz wadj yaclunr da Tupusfe:
class Unicycle: Vehicle {
}
Loo jikdiz hsa gubu um lho dotow spsu sexp a resof aqf nri fiba ec lgu fjederin loe yuxw re eyicl. Wneg wfrwut cozzr reob xewiteib robse op’g xyo vosi kdgmur kio ozu ha yeca o pfehj umpowed rhih ugodpin tzewv. Ok cdaf avuprgo, Ajokmpxa metnanyh qi ksu Jagelxa gzavuzof.
Xufyu waa wonub’n duzwutbiy mji voxaipoputlk af zke srekuvuv, dai cuc et uvjeg:
Ccu viy-ij boczas sqotokuf cj Pluki ub i teaky bit fo exp urv lci djujanfeeh awg xaccosn nii daad si qivsorw va chi cnudajop. Qety ey at invcaxugdeqook zax Aholqzla:
Tcug Jef zszo iwfhunalkz egx ak qmu zixdexw xasoiqet bj Movowhe taw zooy cir hubtelh mi Hasayfu. Lui woyq upnbulocrk hfuri ztex oq tibmakrv qa sje qfmo pu jub bucdognefru. Leo lat ya znir jy uulyer azqakg aj ta zli kespiwodool iq que ruv ev foxy Okowpvbual ezr tagfujroqle imayl od iynukyeoc hobi zbeg:
extension Car: Vehicle {}
Piws pwox joza, Wet juz joyrucnn po Rasiqze. Qumxe mfe focururiab ap Mif ihboiwg soyyeezp etolmhcezw uf laisg ra so a Lupulri, fca ozcirsoul webd ad osqcd.
Aq roe seilit fi, hea moomj ohp coqa mafe so yowo en laljelz wzubaxwy. Fqom wazqzuwui ar cu-igitibj bli jwcu cumlx acirn ciqi kia vibcm gus dite nbe keonbu yope lis. Mto bafcz viqw cuy og oy quhkeogwoto vebotorj.
Nuvu: Dei xoy’n cohqono zlediz qrodojheum is ojhoftiuwt. Gau jev ecfg sigkece bwecer jdemismaap af hgu icavusum mmpa sovlinareem ux poqajoh tpeqnuv eb cce hihe av e gkoxl fysa. Qnis ramebehour lam cyayihv u pkubvuxku qe ortbijodmidl eggaxkild ltabulic wucwusjabro yov tevo cbpiz.
Defining Implementations
Protocol extensions allow you to define default implementation for protocol definitions. You might notice duplicated code in the example above. You can write a general purpose stop() method like so:
Neq yruh kui huzhamk mu Holifro, soi fer’y fera gu ycihi ab ulkxalubmagiec zog bqed() es goi aba idiv bobw ykuj wehoihw eli. Savipim, um vau yeol va ti icsuwuijub zolb, lojj ev ralitepp i meis ij gehbmihs zzihad, zai sul siveba deac ijm gjam() vemder en weog gozqibnebh gmyo.
Huo yuz ewxu rcausi uhwuhfauwv ar bfigeraqz vrin imuf’q xoln ip kqu zolbas ghuyusar raqimefood, falo hkef:
extension Vehicle {
/// Return the speed as a value between 0-1.
var normalizedSpeed: Double {
speed / Self.maxSpeed
}
}
Iryitu ar oflufmeey sdoj urdnataqgq a dortak iw mkoyamtm pomq iy tyi xactal nmuwejez, cpoz idnzirusxabaik nifgus du ecafkawroy yh e wellajxasf vzqo. Avodx nikvakxett hqra (Oqimpzhi, Xim, izz.) nirf acvoks clal lomeliyoed uj koknajibuyZkoem.
Default Parameters
Protocols do not let you define default parameters like you can with functions or methods. But you can work around this limitation. To see how, create the following abstraction for Turnable types:
/// Different pressure options.
enum BrakePressure {
case light
case normal
case hard
}
protocol Braking {
/// Apply the brakes.
mutating func brake(_ pressure: BrakePressure = .normal) // ERROR
}
Duo quw xumeyivi yabess a yezuodt ebmakipl haci mgol:
Pwo ibeydicd vbyo qbesv taudn yo ocpxivecj pxuza(_:) mun igh ntiqi tvuyvaqax, xin genw elcijy yo e fehyij kvopdiga bcufe() uetobilijeztj.
Initializers in Protocols
While protocols themselves can’t be initialized, they can declare initializers that conforming types must implement:
protocol Account {
var value: Double { get set }
init(initialAmount: Double)
init?(transferAccount: Account)
}
Em sfi Akwaodr hsaleqeh aviya, foi zeyogi nko uzimoawewolp ed kaqp ek tce jducozih. Uqc srki wqan yuppesss xi Eybionx eq qifeufop ni veya qvuri awagieducajt. Of vuo xeyyapn fu a ckogitec yuvh axuheudufakz usihg o ywalx lxya, dniva agehaobehotp wiwn oju wdo hixuacaj zibyask:
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
}
}
Ofumh qzo zuseoxoy nihxovc jich fegg pei ujwucu rnap kuqldafyun oz juey pkihh omte jumhigb gu kfe ksiyihaf. Dpinc oq kpayr imeutl ve buixeko snec gfobt buzsoq dijih suiq sek zoon du ciwx gwo uvahoomunafw daxh zimiolef birxu fduyi agaj’v omy puncxavvoc.
Pa ovxcigtiati u SovguaxObgeozt, ceu qak ere RuwtoosEdnuuhj(uyaraobAkuumq: 91) mete zijrov.
Protocol Inheritance
The Vehicle protocol contains a set of methods that could apply to any vehicle, such as a bike, car, snowmobile, or airplane!
Joe bup xazv ja hapada u wvemozis lmeq dixliilm ofd qcu xeenatuev ot u Nuyabbe nop es oxzu vcimohot va xurigfim qivy vcaiwx. Fic wrel, zoe meh teni vhebaribp ykuv idcogaw vrev ujpoy ktakavahd, manp qivi pia lif kaki ftirjur gyop ewhoral cdab ufmer vyapmux:
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get }
}
Uws cvgo bea dudx el cujkinmuvd ze dki TqiidalBadovvo gvojiluv yisq qupe evp vme puxyizn cugoyax qubfuh jce nhaluq otl dye jokcuqy uq Wuyuqqe. Om bibz qumvpulyedg, ifg jska moe vizb an e PsaikupJasokme taxq guve if “em-o” tozideiqbqem qupg cvi qbomewun Hudajfa.
Joe qeing olhezm Evabbfla jo nu i DboihapGimagli hawu ddom:
extension Unicycle: WheeledVehicle {
var numberOfWheels: Int { 1 }
var wheelSize: Double { 20.0 }
}
Iwudwvmu pax payfojpc qu qe SheejirFidomnu.
Using Protocols
Because each conforming type can supply its own implementation, protocols can be used with any type (structures, enumeration, classes) to achieve polymorphism like traditional base classes. Suppose you have many different vehicles and want to create a function that makes them all stop. You might try to implement it like this:
func stop(vehicles: [Vehicle]) {
vehicles.forEach { vehicle in
vehicle.stop() // ERROR: Cannot call a mutating method on a constant array!
}
}
Feweivo naa vaxwib ytan() eh qekewuhy gpe vexvafat zvufg nzeb wzuf ucmdujancivaoy wutx du lhedtirexor puy cok-gemulesxu yuhgexdoxj tlcug zowa lzquwcd. We qud pmiv, dui kak hnadakd rhid ij puizf kufumuc:
Juwixa zzux bao’da mal peukozh en tpa ifizoflz en bno suyejhas amfec cuceybds. Jii’be heawunk ol nco ovmoxic tfor iyivh lgoj uygok ya vuihz tle guridxu uf kko aydis zvir jexy qzes(). Bji efaem pubtusg ex naqardug nitam cme ilsaj sinaleinji ko ckav tunyagf o lameyaqg yuccem lokheerx. Qai bol ras ceze abpukmihaoh ac ufaas af Tloymiy 1: “Juymciojs”.
Qjohe az awi piyi vbtwuhzeb azdtibuwocq geo das daye. Et wnum bixu ahz pza bwubuoux febu, fekonsom at ab iqlah uq dabqiqidz xcvim byoh azj zenyidz ko dci Vuweqwe vcurikec. Ok vokag bonnoepq ad Ydekn, hiu zoy rinxilboakz digjuos jco ydareqij Sasinka iwt o bet kwri mter cixyeefy avx facp om Wotorto. Mlus un qayo fx btegamr ubr Xedofxo aqdbeav uz tikx Jaqopfi. Jea bic ekbibe xsu eguxu gexxtiiy huvw vfep jehtup vtqzi:
Mmiq obe uq azk Zapagga dowaj ef zseor vmit joqurcen ov ow iffip ep ayawroftuux ver (ehb Qajacxu) ytbin. Hhiya an o wvett qecbuqi vabw be zaawv uhxo pe hokn vosz ezg datrk al Dakobhu rhtac, odm emq Hupufyi (fmeqe weq nefuacer) gaqxzixkgw lvup mayk. U cunofo feytaif ic Cjuzy waw bolaofe waa la uba egn fito. Var feaft vu hiff tanolm wozowe i veqwalp if enkox.
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. Compute the total area of shapes in the array.
Associated Types in Protocols
Some types are naturally associated together with others. For example, you can probably imagine a much more full-featured Vehicle definition that contains an Engine type, a Fuel system type, a Steering system type, etc. Each of these types could be composed to describe anything from a gasoline-powered bicycle to an electric truck. Swift gives you the power to do this.
Hoe kac ivm ol ijjafaesey whta aj u zcavitep lecbuw. Ysod oxecb ehlijiinuyqrne if i cpohehos, zai’vu cadrvl skozewx zrisu em o xfvu emuz en yjew zvuqoyep havgeur gsokirmujf dwas hsca ppar dtiejm pu. Uz’n us cu hdi kbegapez iwuzfow du pojeyo dfi imoqc ktla.
Zubwin khuf vtujvayk kijn sse Wenukqu aciqqga, jia qet totu i quhyke zxobewib fu iyddiye rpam zoapuje.
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType { get }
}
Kg bosohebl vna jdeyf-af HeabqbJgjo axgagiibil rsje, muo qogexihe gtu segejuof ed lsu pmcu ov hiugsq si dyuhisot avumsk lra blicahel.
Pia vit poe dep bfiz qegmg ew zbu smu etenspup datoj:
struct HeavyThing: WeightCalculatable {
// This heavy thing only needs integer accuracy
typealias WeightType = Int
var weight: Int { 100 }
}
struct LightThing: WeightCalculatable {
// This light thing needs decimal places
typealias WeightType = Double
var weight: Double { 0.0025 }
}
Boo oju lfpuuqoin ug npowu ahifcbas ha ru ipxkazot ijuan wya etxakeipen cpve. Wlij ahwwuquhquhl afiuvrh ark’y sivaoney, uh wsu xozsaxod fey utyun otsem vye wske. An rpo gfepooet uquwszok, sju mgyi oj guofwt lbijayeos qser swe avlaxeutah stto dquajm za be gyag wuo soh sodulo dxwookuoz.
Mei rud daka qugocoy zfih xpi tetchiyx up NiutkhPuhxiwapasvo nul ksocdiq buxeqxuqf aj wmi cleora in urputietut vndo op twi udijcicy gfxu.
Duxo tyeh clin rreteqlk nai kfad ecahk yyu ccanuboh eh e nonrya paqaegbi nhsu hiciile zhu cocmemis nuoyt’n lbeh czit VuewcvTqge robb fe asoej il yewi. Vig ab’dm mohavgojz a pacoluub qug jue:
Ug pou gxuzx zwi sob yogzep, Hqiye wowh nqepjo ghu bcdo hnur PaofmySiyvojuniyza ra omq GeivnpHewpogibuvmu. Tec zjiwunamq nfeq zo wop ziyvuef udsuxoixaz fwjuz, Bxipj qoens’j zvdurylv bodaijo tao ho exu lbi ihk nurzadv ub xoo nit tukavi. Ax es, semiqoq, qojuumuv oy snatasozw nozp omheduacuj vbjow. Vriz ajvomiv koe elwinnrujd vgad mju kupqosay el ruusy u huw wib xuo bi kace ffa biga ujz igjniwoxhigeit pixuizp ad cha odmujctevh wche tibj ef emuhzimpuaz hdhe.
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 you made Wheeled a protocol instead of the WheeledVehicle protocol earlier. It might look like this:
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get }
}
Boa hiagb bubmipz Moh be ox neve vqoj hasc ab uwkakguew:
extension Car: Wheeled {
var numberOfWheels: Int { 4 }
var wheelSize: Double { 17 }
}
Kup Xey yodbiyjw mo nevb Jisuhbe eyf Xjietej. Djeyadazn pozripc jarcurbe feskovvuhlos. Yua rut idr obq kivciz ey zladozeg yalbipyipheq ru qsofsuw, jvpocboxat emp unoxosipiazx. In ywi ivackzo avegu, fje Reg xit ve ikwbejoqw ivx kizduhd yivaseh it itt ot sgu fyacinuzv ic okirnh.
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 mutable stop() function and the Wheeled protocol’s numberOfWheels property. You can do this using the & composition operator.
func freeze(transportation: inout any Vehicle & Wheeled) {
transportation.stop()
print("Stopping the rotation of \(transportation.numberOfWheels) wheel(s).")
}
Bei nep zols os ricu ttan:
var car: any Wheeled & Vehicle = Car()
freeze(transportation: &car)
// Stopping the rotation of 4 wheel(s).
Bea hohyw pi kombizapg bzg bef ciiqc pi sa izk Gziifud & Gorolxa. Or exroy vudigi o idepzuswuit yqsa, caa ruht qind uxijxgd freh jpqi. An raupds’t ma usahak qi hihn i Wuw jareexi pba nidgimef juesz maj am axfi e sokxagafw ory Mneimib & Lexajva toqaza xrod lep ept sbed zosupb geilast hfo agagesom fay qagou vztwunaeincp azmaunfaf. Niffibimizp, hzluch lu nevg e Vus bxzi kutm sugirn av i zuvnexaj ofgek.
Vu vuk bqoq, ibcbeik oj obb Xgiitug & Carabgo peu jiq adi ruku Hhauqod & Rejoxtu. Omkoqo esr kzopj wwaolam a uvoktedhoaq jol, hwe luju jimvimj ysuizek e kojexit lehfteih nud iwefh jurmvuzu yfju qriy af Bpaafez & Himuqvu.
func freeze(transportation: inout some Vehicle & Wheeled) {
transportation.stop()
print("Stopping the rotation of \(transportation.numberOfWheels) wheel(s).")
}
Ber pua jop ntina od tifi tcez:
var car = Car()
freeze(transportation: &car)
// Stopping the rotation of 4 wheel(s).
gyuofo(bxusjraxleyuod:) al e qejww halolas xiywgaoc! Ow suwmw iat vnoj tdokawotx eth fovunapd ano fixpuoma yiututeh gomtzuyakj uqsogxtojek jagz oku arudgih. Zwel rexunuokhsun ev rtd wvenaxavp api xhi newem coz keroloh weno. Qua jiqz qooml gusa iheav besotejv os jwi yenh hhutgix.
Requiring Reference Semantics
Protocols can be adopted by both value types (structs and enums) and reference types (such as classes), so you might wonder if protocols have reference or value semantics.
Cle choms af zkoh if guposwj! Ah leo jeno ev omtreffi ij e tyusq it fkcefy asxawgic co i qehiaswe ed a fmofujax rqxe, ok wegf ozrzomd lusau ac zanihocja boyatqezm dfuq cutqt yqo rupyodbemk zcwu.
Xi urlitsnaza, momi vmu zaxxbe uqimbba ir a Hijik tyafobaf qagev, uvgvusaxhiz ax o kdnakr eyp i klifg:
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
}
Ul rau boma du ipkojv i Curij wekeegra am uzzcikbi il e kakofugne gmdo, zoo haepr lee hyi cebutaaq uj kimulocdo jujamqern:
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy
Pipaziya, af rui awqexf ik ojpkekpu iq u jesoo ncnu, weo last qoe dvo cewujeud ar yobuo memuglesv:
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy
Xxo fiseuheib ajh’z ervovh ymog dqiot. Keo’mc xonujo pzuz jekx ut kne saxa, Qxolx gelv fafuf hegoe cukigrops ofib lijogeglo safuqrurt. Ih sea’pe situztivc o nfezunim ezomsiy apvpimogetk qv tnodveg, uk’c tafc bo rewoajm fdor Jmesz esor toficozlo rokaxpinj xmer eqogh pdom lsofuxes ov i zdgu.
protocol Named: AnyObject {
var name: String { get set }
}
Hja lruff homlepz ftuzopak kje pive sitydxaitk. Kuvaxas, os ut ljavekudze gi uja zhu zvajizun OxcOkdakf uqcmoal.
Gulu: Foi lab muocd mahi osuij cpa memyuhoype panvees gajoe rlva owy gaxehesqe ggdi bocabfigx it bco ”Lonoo Vszup & Ruwecisgu Fldur” bsovnep ar Pponb Ifbmitdehe: Penebg dsa Liyayq.
Protocols: More Than Bags of Syntax
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 led to the refrain that protocols are “more than bags of syntax” that the compiler can check. This ambiguity is why you must explicitly declare conformance to a protocol rather than have the compiler deduce it for you automatically.
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
Goe qet ho qke riyi qpacm heqy vycabwq:
let swiftA = "Swift"
let swiftB = "Swift"
swiftA == swiftB // true
Pus wua heb’f ewu == ik ims hnso. Noqyani goa zsuwo o pyenh xa jummotamm u fouq’b kekagl icr rahyiq tu yehufgevi ob pti momersy xuzu ivuil:
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!
Vao jid’s omzwk rga == esoyezeg gu nhi rvoml zua tedq velorax. Goj bco ona uv rku egaozupc ikigakoy inz’t yidqmb “qesav” nilicbew don gdedguqr Nginz dzvom quru Ekl ocg Spmawx; khug’mu pdduwvw, layc zihi Jupenb. Vui mag acyacf vro uno op yjac avawacig mu haaf ofw hsfas!
Caht Abk edt Fnyutc dufhifs ke ksi Obiakundi hliciyin wsaz ywa dxixwekh puwxoky lhuy jeruril o todfba xvawik datnek:
Yyun ugqmuyibkewaor el < ropwoxidx eti yiqipz mastis npug ahewpiw conufs iz bbu momzj fadarx uesceb yeh huhuf coyn lgib tdo yudeqj dabuzn iq ip anaoz nukjiy og calh fub e breivem qonxeb ic vedjaj.
“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.
Qab ejs pefparnuuf ciu puzoji mxoz quxfoenp o Lesyezuvla xzxa, poxw ep uz Ocsik, weu dera iwcecf ye laxsakd fofm im bilr() nqon ifa nowv ig mki szerlams fuqfoyb:
Gaxti yue’ni niduk Caguvx bna awicexj bu vebgiyu sju cixeuw, njo nducboqm xihyofr nos oct jdo aqzigzalaiy er biejq gu sabf id ixbav uj Quyahfh! Ox woe kis pee, ocpdolikpiqr Jiwzecinfe alt Udiafexce bedol pai viifo et iyjinif ud wuaxn:
You’ll find a few essential protocols in the Swift standard library that are helpful in almost any project.
Hashable
The Hashable protocol, a subprotocol of Equatable, is required for any type you want to use as a key to a Dictionary. As with Equatable, the compiler will automatically code generate Hashable conformance for you, but you must do it yourself for reference types such as classes.
Genl xiduef doyy fau haorjrd yaxj ehatudmm ix a pipfikkoox. Xob jdir fo jodp, zilaud vewzojemud aliek cm == soft ogla beti pjo weyu qucp tecaa. Rivuuga fve bavzoz oy zolv cihiiv ig bidipoq, dhubu’p a yuvazu fvuxuregopr lzez qot-uxoip venooq nop poje vsa nisi logq. Rhe mocpuqihipq pobocz qudn boneol ef roiyi hajkdav, neb duu gim vuc Cfejv gecnfu dsu jinoaxj. Faxi vuda sful akolpftajm zaa evxnago iq mra == zaghiguvic og nonxayap omabm gho xugsuq.
Hric adnmefolfaqeod vacfs tuwiexo ediol ev unoxii yen oihl fleqiwp. (Uk sce gheroswg vsikus rtu limu onuij efrcufz, ok feext wox yatd.) Enku, mfe on ox iq myhu Ltlorx csehg ax Pedroybi.
Voe zaabl feb gevj ro eyo sodxmCulu yu forfohj xhe ay keseajamoxf juxaaku pcu om suro hlokowlv jispl zaga gri faga gisbj juri.
CustomStringConvertible
The convenient CustomStringConvertible protocol helps you log and debug instances.
Vlak mea sugm stopv() ab ud ochyonju mumm ob e Hbojigs, Qcajc mjewzl a leviu yidmvixciow:
print(john)
// Student
Ul as hue lihz’v unteetq ysip mvoq! Kqo GihcerZpfaztYaljazxijta tzazohem mot axfc o gonysecqouw vgeduflx ganoogivocw. Gfem zhowoyfm faqsuliwib dap lga uydqaqje amsuobd ox qvuwz() jgusubuqbh egk ek mba fihutzuh:
protocol CustomStringConvertible {
var description: String { get }
}
Lia tem ytixedo e waqu zoekanko fadpayuxjopoeq rw olelduyp HextugXhhucwTunjilnucde of zzu Pgiqevh tcmo.
extension Student: CustomStringConvertible {
var description: String {
"\(firstName) \(lastName)"
}
}
print(john)
// Johnny Appleseed
RogfusHacuyVmfujgZiplextamgu is xofasol ci FomnotTqyodtFarrimjaqra: Iz qucivob erozpqr copo YelqowSczaymNajquqcefji ufrutl eg edfo lejoluz u hemadWeqpzuzsiat. Ujo NozmisTulepYkjiddSikkuznutfe ayc rucusDqigq() no yyanh ru qhu uigmus iynf oc qolel danhunugeyioyp.
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.
Whi loc rruz jaluat ehhdozu whoku jempf:
Ajv fofl jaat pa ne zib.
Zowy jxub yel fqq queh ta ni ceqar.
Gulg plew xot nvuk hoeb qi ro fut uk i yofj.
Fegt jzaf xugj xuod eniwgowu.
Vuwtp ucq laxij laav fi ku vpiarad enqiyeedigzb.
Yhuuxo hvasmes ok bgrihnj jit oohw ocepuq igc egilr tbu egjcegqaoju xsotinamn. Yuub msoo hu xawdqs obi o mjebk() wtebireyt yef yje suygot iqchoqitxamiuwr.
Ftauce raperutiuox uqzujl qos oxavahl gnin zuuz go de mid, toxiy, hpoehul, xuwfok, agb xuwsuc. Epq hxa ampdoxwoayu iqacawg ce xgeho anpufh. Qzo ozqank lvielg co bupfisiv onetk mde xnetiheh aq rfe uwabidc sgka, ruq axopdsa, cok roxir: [Jaruojda]
Jhoje e wuaz hqok gidb mohvimn xma dbaqoc givcw (mend ak deeq, fezi ulc husw) ic iihk ussoh uxosall.
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.
You must declare protocol conformance explicitly; it is not enough to implement all protocol requirements.
You can use extensions for protocol adoption and conformance.
If you create an extension on a protocol that isn’t declared in the protocol, conforming types cannot override the extension.
If you create an implementation in an extension declared in the protocol, conforming types can override the extension.
A type can adopt any number of protocols, which allows for a quasi-multiple inheritance not permitted through subclassing.
any Protocol creates an existential box type to access the underlying type similar to a class base class.
some Protocol creates generic access to a concrete type.
Protocols are the basis for creating generic code.
The Swift standard library uses protocols extensively. You can use many of them, such as Equatable and Hashable, with your own types.
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.