Protokol je zelo močna značilnost Hitri programski jezik .
primeri avtentikacije na podlagi žetonov
Protokoli se uporabljajo za opredelitev 'načrta metod, lastnosti in drugih zahtev, ki ustrezajo določeni nalogi ali delu funkcionalnosti.'
Hitra preverjanja težav s skladnostjo protokola v času prevajanja omogoča razvijalcem, da odkrijejo nekaj usodnih napak v kodi, še preden zaženejo program. Protokoli omogočajo razvijalcem, da v Swiftu pišejo prilagodljivo in razširljivo kodo, ne da bi morali ogrožati izraznost jezika.
Swift poenostavi uporabo protokolov še korak dlje, tako da ponuja rešitve nekaterih najpogostejših domislic in omejitev vmesnikov, ki pestijo številne druge programske jezike.
V prejšnjih različicah Swifta je bilo mogoče razširiti le razrede, strukture in enume, kot velja za številne sodobne programske jezike. Od različice 2 Swifta pa je bilo mogoče razširiti tudi protokole.
Ta članek preučuje, kako lahko protokole v Swiftu uporabljamo za pisanje kode, ki jo je mogoče večkrat uporabiti in jo je mogoče vzdrževati, in kako lahko spremembe velike protokolarno naravnane kode združimo na eno mesto z uporabo razširitev protokola.
Kaj je protokol?
V svoji najpreprostejši obliki je protokol vmesnik, ki opisuje nekatere lastnosti in metode. Vsak tip, ki ustreza protokolu, mora posebne lastnosti, opredeljene v protokolu, izpolniti z ustreznimi vrednostmi in uporabiti potrebne metode. Na primer:
protocol Queue { var count: Int { get } mutating func push(_ element: Int) mutating func pop() -> Int }
Protokol Čakalna vrsta opisuje čakalno vrsto, ki vsebuje celoštevilčne elemente. Sintaksa je povsem enostavna.
Znotraj bloka protokola, ko opisujemo lastnost, moramo določiti, ali je lastnost dostopna samo { get }
ali tako dobljiv kot nastavljiv { get set }
. V našem primeru je spremenljivko Count (vrste Int
) mogoče dobiti le.
Če protokol zahteva, da je lastnost dostopna in nastavljiva, te zahteve ne more izpolniti stalna shranjena lastnost ali izračunana lastnost samo za branje.
Če protokol zahteva samo, da je lastnost dostopna, lahko zahtevo izpolni katera koli lastnost in velja, da jo je mogoče nastaviti tudi, če je to koristno za vašo kodo.
Za funkcije, opredeljene v protokolu, je pomembno, da s funkcijo mutating
navedete, ali bo funkcija spremenila vsebino ključna beseda. Razen tega podpis funkcije zadošča kot definicija.
Za skladnost s protokolom mora tip zagotoviti vse lastnosti primerka in implementirati vse metode, opisane v protokolu. Spodaj je na primer struktura Container
ki ustreza našemu Queue
protokol. Struktura v bistvu shranjuje potisnjene Int
s v zasebno polje items
.
struct Container: Queue { private var items: [Int] = [] var count: Int { return items.count } mutating func push(_ element: Int) { items.append(element) } mutating func pop() -> Int { return items.removeFirst() } }
Naš trenutni protokol čakalne vrste pa ima veliko pomanjkljivost.
Samo protokoli, ki obravnavajo Int
s, so lahko v skladu s tem protokolom.
To omejitev lahko odstranimo z uporabo funkcije 'pridružene vrste'. Povezane vrste delujejo kot generiki. Za prikaz naj spremenimo protokol čakalne vrste, da bo uporabil povezane vrste:
protocol Queue { associatedtype ItemType var count: Int { get } func push(_ element: ItemType) func pop() -> ItemType }
Zdaj protokol Queue omogoča shranjevanje kaj vrsta predmetov.
Pri izvajanju Container
strukturo, prevajalnik določi pripadajoči tip iz konteksta (tj. vrsto vrnitve metode in vrste parametrov). Ta pristop nam omogoča ustvariti Container
struktura z generičnim tipom elementov. Na primer:
class Container: Queue { private var items: [Item] = [] var count: Int { return items.count } func push(_ element: Item) { items.append(element) } func pop() -> Item { return items.removeFirst() } }
Uporaba protokolov v mnogih primerih poenostavi pisanje kode.
Na primer, vsak objekt, ki predstavlja napako, je lahko v skladu z Error
(ali LocalizedError
, če želimo zagotoviti lokalizirane opise).
Potem se lahko enaka logika obravnave napak uporabi za katerega koli od teh objektov napak v celotni kodi. Posledično vam za predstavitev napak ni treba uporabiti nobenega določenega predmeta (na primer NSError v Objective-C), lahko uporabite katero koli vrsto, ki ustreza Error
ali LocalizedError
protokoli.
Tip String lahko celo razširite, da se prilagodi LocalizedError
protokol in vrzi nize kot napake.
extension String: LocalizedError { public var errorDescription: String? { Return NSLocalizedString(self, comment:””) } } throw “Unfortunately something went wrong” func handle(error: Error) { print(error.localizedDescription) }
Razširitve protokolov temeljijo na neverjetnosti protokolov. Omogočajo nam:
Zagotovite privzeto izvedbo metod protokola in privzete vrednosti lastnosti protokola, s čimer jih naredite 'neobvezno'. Vrste, ki ustrezajo protokolu, lahko zagotovijo lastne izvedbe ali uporabljajo privzete.
Dodajte izvajanje dodatnih metod, ki niso opisane v protokolu, in »okrasite« vse tipe, ki ustrezajo protokolu, s temi dodatnimi metodami. Ta funkcija nam omogoča, da več vrstam, ki so že v skladu s protokolom, dodamo posebne metode, ne da bi morali vsako vrsto posebej spreminjati.
Ustvarimo še en protokol:
protocol ErrorHandler { func handle(error: Error) }
Ta protokol opisuje predmete, ki so odgovorni za obdelavo napak, ki se pojavijo v aplikaciji. Na primer:
struct Handler: ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } }
Tu samo natisnemo lokaliziran opis napake. Z razširitvijo protokola lahko omogočimo, da je ta izvedba privzeta.
extension ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } }
S tem naredite handle
neobvezna metoda z zagotavljanjem privzete izvedbe.
Zmožnost razširitve obstoječega protokola s privzetim vedenjem je precej močna, kar omogoča, da protokoli rastejo in se razširijo, ne da bi se morali skrbeti za prekinitev združljivosti obstoječe kode.
predlogo dokumenta za oblikovanje na visoki ravni
Tako smo zagotovili privzeto izvedbo handle
metoda, vendar tiskanje na konzolo končnemu uporabniku ni v veliko pomoč.
Verjetno bi jim raje prikazali nekakšen opozorilni pogled z lokaliziranim opisom, kadar je upravljavec napak krmilnik pogleda. Za to lahko podaljšamo ErrorHandler
protokol, lahko pa omeji razširitev, da velja samo za določene primere (tj. kadar je tip krmilnik pogleda).
Swift nam omogoča, da takšne pogoje dodamo razširitvam protokola z uporabo where
ključna beseda.
extension ErrorHandler where Self: UIViewController { func handle(error: Error) { let alert = UIAlertController(title: nil, message: error.localizedDescription, preferredStyle: .alert) let action = UIAlertAction(title: 'OK', style: .cancel, handler: nil) alert.addAction(action) present(alert, animated: true, completion: nil) } }
Jaz (z veliko »S«) v zgornjem delčku kode se nanaša na vrsto (strukturo, razred ali enum). Z navedbo, da protokol razširjamo samo za tipe, ki podedujejo iz UIViewController
, lahko uporabimo UIViewController
posebne metode (na primer present(viewControllerToPresnt: animated: completion)
).
Zdaj so vsi krmilniki pogleda, ki ustrezajo ErrorHandler
protokol imajo svojo privzeto izvedbo handle
metoda, ki prikazuje pogled opozorila z lokaliziranim opisom.
Predpostavimo, da obstajata dva protokola, ki imata metodo z enakim podpisom.
protocol P1 { func method() //some other methods } protocol P2 { func method() //some other methods }
Oba protokola imata razširitev s privzeto izvedbo te metode.
extension P1 { func method() { print('Method P1') } } extension P2 { func method() { print('Method P2') } }
Zdaj pa predpostavimo, da obstaja tip, ki ustreza obema protokoloma.
struct S: P1, P2 { }
V tem primeru imamo težavo z dvoumno izvedbo metode. Tip ne označuje jasno, katero izvedbo metode bi moral uporabiti. Kot rezultat dobimo napako pri prevajanju. Da bi to popravili, moramo tipu dodati izvedbo metode.
struct S: P1, P2 { func method() { print('Method S') } }
Številni objektno usmerjeni programski jeziki trpijo zaradi omejitev glede ločljivosti dvoumnih definicij razširitev. Swift to povsem elegantno obravnava s pomočjo razširitev protokola, tako da programerju omogoči, da prevzame nadzor, kadar prevajalnik ne uspe.
Oglejmo si Queue
protokol še enkrat.
protocol Queue { associatedtype ItemType var count: Int { get } func push(_ element: ItemType) func pop() -> ItemType }
Vsak tip, ki ustreza Queue
protokol ima count
lastnost primerka, ki definira število shranjenih elementov. To nam med drugim omogoča primerjavo takšnih vrst in odločitev, katera je večja. To metodo lahko dodamo s podaljšanjem protokola.
extension Queue { func compare(queue: Q) -> ComparisonResult where Q: Queue { if count queue.count { return .orderedAscending } return .orderedSame } }
Ta metoda ni opisana v Queue
protokol, ker ni povezan s funkcijo čakalne vrste.
Zato to ni privzeta izvedba metode protokola, temveč je nova izvedba metode, ki 'okrasi' vse vrste, ki ustrezajo Queue
protokol. Brez razširitev protokola bi morali to metodo dodati vsaki vrsti posebej.
Razširitve protokola se morda zdijo precej podobne uporabi osnovnega razreda, vendar ima uporaba razširitev protokola več prednosti. Ti vključujejo, vendar niso nujno omejeni na:
Ker lahko razredi, strukture in naštevanja ustrezajo več kot enemu protokolu, lahko sprejmejo privzeto izvedbo več protokolov. To je konceptualno podobno večkratnemu dedovanju v drugih jezikih.
Razrede, strukture in enume lahko sprejmejo protokole, medtem ko so osnovni razredi in dedovanje na voljo samo za razrede.
Poleg razširitve lastnih protokolov lahko protokole razširite tudi iz standardne knjižnice Swift. Če želimo na primer najti povprečno velikost zbirke čakalnih vrst, lahko to storimo tako, da razširimo standard Collection
protokol.
Podatkovne strukture zaporedja, ki jih zagotavlja Swiftova standardna knjižnica, do katerih elementov je mogoče dostopati in dostopati prek indeksiranega podpisnika, običajno ustrezajo Collection
protokol. S podaljšanjem protokola je mogoče razširiti vse takšne standardne strukture knjižničnih podatkov ali jih nekaj razširiti selektivno.
Opomba: Protokol, prej znan kot
CollectionType
v Swiftu 2.x je bil preimenovan vCollection
v Swiftu 3.
extension Collection where Iterator.Element: Queue { func avgSize() -> Int { let size = map { Uvod v protokolarno programiranje v Swiftu
Protokol je zelo močna značilnost Hitri programski jezik .
Protokoli se uporabljajo za opredelitev 'načrta metod, lastnosti in drugih zahtev, ki ustrezajo določeni nalogi ali delu funkcionalnosti.'
Hitra preverjanja težav s skladnostjo protokola v času prevajanja omogoča razvijalcem, da odkrijejo nekaj usodnih napak v kodi, še preden zaženejo program. Protokoli omogočajo razvijalcem, da v Swiftu pišejo prilagodljivo in razširljivo kodo, ne da bi morali ogrožati izraznost jezika.
Swift poenostavi uporabo protokolov še korak dlje, tako da ponuja rešitve nekaterih najpogostejših domislic in omejitev vmesnikov, ki pestijo številne druge programske jezike.
V prejšnjih različicah Swifta je bilo mogoče razširiti le razrede, strukture in enume, kot velja za številne sodobne programske jezike. Od različice 2 Swifta pa je bilo mogoče razširiti tudi protokole.
Ta članek preučuje, kako lahko protokole v Swiftu uporabljamo za pisanje kode, ki jo je mogoče večkrat uporabiti in jo je mogoče vzdrževati, in kako lahko spremembe velike protokolarno naravnane kode združimo na eno mesto z uporabo razširitev protokola.
Kaj je protokol?
V svoji najpreprostejši obliki je protokol vmesnik, ki opisuje nekatere lastnosti in metode. Vsak tip, ki ustreza protokolu, mora posebne lastnosti, opredeljene v protokolu, izpolniti z ustreznimi vrednostmi in uporabiti potrebne metode. Na primer:
protocol Queue { var count: Int { get } mutating func push(_ element: Int) mutating func pop() -> Int }
Protokol Čakalna vrsta opisuje čakalno vrsto, ki vsebuje celoštevilčne elemente. Sintaksa je povsem enostavna.
Znotraj bloka protokola, ko opisujemo lastnost, moramo določiti, ali je lastnost dostopna samo { get }
ali tako dobljiv kot nastavljiv { get set }
. V našem primeru je spremenljivko Count (vrste Int
) mogoče dobiti le.
Če protokol zahteva, da je lastnost dostopna in nastavljiva, te zahteve ne more izpolniti stalna shranjena lastnost ali izračunana lastnost samo za branje.
Če protokol zahteva samo, da je lastnost dostopna, lahko zahtevo izpolni katera koli lastnost in velja, da jo je mogoče nastaviti tudi, če je to koristno za vašo kodo.
Za funkcije, opredeljene v protokolu, je pomembno, da s funkcijo mutating
navedete, ali bo funkcija spremenila vsebino ključna beseda. Razen tega podpis funkcije zadošča kot definicija.
Za skladnost s protokolom mora tip zagotoviti vse lastnosti primerka in implementirati vse metode, opisane v protokolu. Spodaj je na primer struktura Container
ki ustreza našemu Queue
protokol. Struktura v bistvu shranjuje potisnjene Int
s v zasebno polje items
.
struct Container: Queue { private var items: [Int] = [] var count: Int { return items.count } mutating func push(_ element: Int) { items.append(element) } mutating func pop() -> Int { return items.removeFirst() } }
Naš trenutni protokol čakalne vrste pa ima veliko pomanjkljivost.
Samo protokoli, ki obravnavajo Int
s, so lahko v skladu s tem protokolom.
To omejitev lahko odstranimo z uporabo funkcije 'pridružene vrste'. Povezane vrste delujejo kot generiki. Za prikaz naj spremenimo protokol čakalne vrste, da bo uporabil povezane vrste:
protocol Queue { associatedtype ItemType var count: Int { get } func push(_ element: ItemType) func pop() -> ItemType }
Zdaj protokol Queue omogoča shranjevanje kaj vrsta predmetov.
Pri izvajanju Container
strukturo, prevajalnik določi pripadajoči tip iz konteksta (tj. vrsto vrnitve metode in vrste parametrov). Ta pristop nam omogoča ustvariti Container
struktura z generičnim tipom elementov. Na primer:
class Container: Queue { private var items: [Item] = [] var count: Int { return items.count } func push(_ element: Item) { items.append(element) } func pop() -> Item { return items.removeFirst() } }
Uporaba protokolov v mnogih primerih poenostavi pisanje kode.
Na primer, vsak objekt, ki predstavlja napako, je lahko v skladu z Error
(ali LocalizedError
, če želimo zagotoviti lokalizirane opise).
Potem se lahko enaka logika obravnave napak uporabi za katerega koli od teh objektov napak v celotni kodi. Posledično vam za predstavitev napak ni treba uporabiti nobenega določenega predmeta (na primer NSError v Objective-C), lahko uporabite katero koli vrsto, ki ustreza Error
ali LocalizedError
protokoli.
Tip String lahko celo razširite, da se prilagodi LocalizedError
protokol in vrzi nize kot napake.
extension String: LocalizedError { public var errorDescription: String? { Return NSLocalizedString(self, comment:””) } } throw “Unfortunately something went wrong” func handle(error: Error) { print(error.localizedDescription) }
Razširitve protokolov temeljijo na neverjetnosti protokolov. Omogočajo nam:
Zagotovite privzeto izvedbo metod protokola in privzete vrednosti lastnosti protokola, s čimer jih naredite 'neobvezno'. Vrste, ki ustrezajo protokolu, lahko zagotovijo lastne izvedbe ali uporabljajo privzete.
Dodajte izvajanje dodatnih metod, ki niso opisane v protokolu, in »okrasite« vse tipe, ki ustrezajo protokolu, s temi dodatnimi metodami. Ta funkcija nam omogoča, da več vrstam, ki so že v skladu s protokolom, dodamo posebne metode, ne da bi morali vsako vrsto posebej spreminjati.
Ustvarimo še en protokol:
protocol ErrorHandler { func handle(error: Error) }
Ta protokol opisuje predmete, ki so odgovorni za obdelavo napak, ki se pojavijo v aplikaciji. Na primer:
struct Handler: ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } }
Tu samo natisnemo lokaliziran opis napake. Z razširitvijo protokola lahko omogočimo, da je ta izvedba privzeta.
extension ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } }
S tem naredite handle
neobvezna metoda z zagotavljanjem privzete izvedbe.
Zmožnost razširitve obstoječega protokola s privzetim vedenjem je precej močna, kar omogoča, da protokoli rastejo in se razširijo, ne da bi se morali skrbeti za prekinitev združljivosti obstoječe kode.
Tako smo zagotovili privzeto izvedbo handle
metoda, vendar tiskanje na konzolo končnemu uporabniku ni v veliko pomoč.
Verjetno bi jim raje prikazali nekakšen opozorilni pogled z lokaliziranim opisom, kadar je upravljavec napak krmilnik pogleda. Za to lahko podaljšamo ErrorHandler
protokol, lahko pa omeji razširitev, da velja samo za določene primere (tj. kadar je tip krmilnik pogleda).
Swift nam omogoča, da takšne pogoje dodamo razširitvam protokola z uporabo where
ključna beseda.
extension ErrorHandler where Self: UIViewController { func handle(error: Error) { let alert = UIAlertController(title: nil, message: error.localizedDescription, preferredStyle: .alert) let action = UIAlertAction(title: 'OK', style: .cancel, handler: nil) alert.addAction(action) present(alert, animated: true, completion: nil) } }
Jaz (z veliko »S«) v zgornjem delčku kode se nanaša na vrsto (strukturo, razred ali enum). Z navedbo, da protokol razširjamo samo za tipe, ki podedujejo iz UIViewController
, lahko uporabimo UIViewController
posebne metode (na primer present(viewControllerToPresnt: animated: completion)
).
Zdaj so vsi krmilniki pogleda, ki ustrezajo ErrorHandler
protokol imajo svojo privzeto izvedbo handle
metoda, ki prikazuje pogled opozorila z lokaliziranim opisom.
Predpostavimo, da obstajata dva protokola, ki imata metodo z enakim podpisom.
protocol P1 { func method() //some other methods } protocol P2 { func method() //some other methods }
Oba protokola imata razširitev s privzeto izvedbo te metode.
extension P1 { func method() { print('Method P1') } } extension P2 { func method() { print('Method P2') } }
Zdaj pa predpostavimo, da obstaja tip, ki ustreza obema protokoloma.
struct S: P1, P2 { }
V tem primeru imamo težavo z dvoumno izvedbo metode. Tip ne označuje jasno, katero izvedbo metode bi moral uporabiti. Kot rezultat dobimo napako pri prevajanju. Da bi to popravili, moramo tipu dodati izvedbo metode.
struct S: P1, P2 { func method() { print('Method S') } }
Številni objektno usmerjeni programski jeziki trpijo zaradi omejitev glede ločljivosti dvoumnih definicij razširitev. Swift to povsem elegantno obravnava s pomočjo razširitev protokola, tako da programerju omogoči, da prevzame nadzor, kadar prevajalnik ne uspe.
Oglejmo si Queue
protokol še enkrat.
protocol Queue { associatedtype ItemType var count: Int { get } func push(_ element: ItemType) func pop() -> ItemType }
Vsak tip, ki ustreza Queue
protokol ima count
lastnost primerka, ki definira število shranjenih elementov. To nam med drugim omogoča primerjavo takšnih vrst in odločitev, katera je večja. To metodo lahko dodamo s podaljšanjem protokola.
extension Queue { func compare(queue: Q) -> ComparisonResult where Q: Queue { if count queue.count { return .orderedAscending } return .orderedSame } }
Ta metoda ni opisana v Queue
protokol, ker ni povezan s funkcijo čakalne vrste.
Zato to ni privzeta izvedba metode protokola, temveč je nova izvedba metode, ki 'okrasi' vse vrste, ki ustrezajo Queue
protokol. Brez razširitev protokola bi morali to metodo dodati vsaki vrsti posebej.
Razširitve protokola se morda zdijo precej podobne uporabi osnovnega razreda, vendar ima uporaba razširitev protokola več prednosti. Ti vključujejo, vendar niso nujno omejeni na:
Ker lahko razredi, strukture in naštevanja ustrezajo več kot enemu protokolu, lahko sprejmejo privzeto izvedbo več protokolov. To je konceptualno podobno večkratnemu dedovanju v drugih jezikih.
Razrede, strukture in enume lahko sprejmejo protokole, medtem ko so osnovni razredi in dedovanje na voljo samo za razrede.
Poleg razširitve lastnih protokolov lahko protokole razširite tudi iz standardne knjižnice Swift. Če želimo na primer najti povprečno velikost zbirke čakalnih vrst, lahko to storimo tako, da razširimo standard Collection
protokol.
Podatkovne strukture zaporedja, ki jih zagotavlja Swiftova standardna knjižnica, do katerih elementov je mogoče dostopati in dostopati prek indeksiranega podpisnika, običajno ustrezajo Collection
protokol. S podaljšanjem protokola je mogoče razširiti vse takšne standardne strukture knjižničnih podatkov ali jih nekaj razširiti selektivno.
Opomba: Protokol, prej znan kot
CollectionType
v Swiftu 2.x je bil preimenovan vCollection
v Swiftu 3.
extension Collection where Iterator.Element: Queue { func avgSize() -> Int { let size = map { $0.count }.reduce(0, +) return Int(round(Double(size) / Double(count.toIntMax()))) } }
Zdaj lahko izračunamo povprečno velikost katere koli zbirke čakalnih vrst (Array
, Set
itd.). Brez razširitev protokola bi morali to metodo dodati vsaki vrsti zbirke posebej.
V standardni knjižnici Swift se za razširitev protokola uporabljajo na primer metode, kot so map
, filter
, reduce
itd.
extension Collection { public func map(_ transform: (Self.Iterator.Element) throws -> T) rethrows -> [T] { } }
Kot sem že omenil, nam razširitve protokolov omogočajo dodajanje privzetih izvedb nekaterih metod in dodajanje novih izvedb metod. Kakšna pa je razlika med tema dvema značilnostma? Vrnimo se k upravljavcu napak in ugotovimo.
protocol ErrorHandler { func handle(error: Error) } extension ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } } struct Handler: ErrorHandler { func handle(error: Error) { fatalError('Unexpected error occurred') } } enum ApplicationError: Error { case other } let handler: Handler = Handler() handler.handle(error: ApplicationError.other)
Rezultat je usodna napaka.
Zdaj odstranite handle(error: Error)
izjava metode iz protokola.
protocol ErrorHandler { }
Rezultat je enak: usodna napaka.
Ali to pomeni, da ni razlike med dodajanjem privzete izvedbe metode protokola in dodajanjem nove izvedbe metode protokolu?
Ne! Razlika obstaja in to lahko vidite, če spremenite vrsto spremenljivke handler
od Handler
do ErrorHandler
.
let handler: ErrorHandler = Handler()
Zdaj je izhod v konzolo: Operacije ni bilo mogoče dokončati. (Napaka ApplicationError 0.)
Če pa protokolu vrnemo deklaracijsko metodo ročaja (error: Error), se bo rezultat spremenil nazaj v usodno napako.
protocol ErrorHandler { func handle(error: Error) }
Oglejmo si vrstni red dogajanja v posameznem primeru.
Ko v protokolu obstaja izjava metode:
Protokol označuje handle(error: Error)
metoda in zagotavlja privzeto izvedbo. Metoda je razveljavljena v Handler
izvajanje. Torej se med izvajanjem prikliče pravilna izvedba metode, ne glede na vrsto spremenljivke.
Če izjava metode v protokolu ne obstaja:
Ker metoda ni deklarirana v protokolu, je tip ne more preglasiti. Zato je izvedba klicane metode odvisna od vrste spremenljivke.
Če je spremenljivka tipa Handler
, se pokliče izvedba metode iz tipa. Če je spremenljivka tipa ErrorHandler
, se pokliče izvedba metode iz razširitve protokola.
V tem članku smo pokazali nekaj moči razširitev protokola v Swiftu.
Za razliko od drugih programskih jezikov z vmesniki, Swift ne omejuje protokolov z nepotrebnimi omejitvami. Swift se ukvarja s splošnimi domislicami teh programskih jezikov, tako da razvijalcu omogoča, da po potrebi razreši dvoumnosti.
S protokoli Swift in razširitvami protokolov je koda, ki jo napišete, lahko tako izrazita kot večina dinamičnih programskih jezikov in je v času prevajanja še vedno varna za tip. To vam omogoča, da zagotovite ponovno uporabo in vzdrževanje kode ter da bolj samozavestno spreminjate kodno bazo aplikacije Swift.
Upamo, da vam bo ta članek koristen in pozdravljamo kakršne koli povratne informacije ali nadaljnja spoznanja.
Zdaj lahko izračunamo povprečno velikost katere koli zbirke čakalnih vrst (Array
, Set
itd.). Brez razširitev protokola bi morali to metodo dodati vsaki vrsti zbirke posebej.
V standardni knjižnici Swift se za razširitev protokola uporabljajo na primer metode, kot so map
, filter
, reduce
itd.
ionski 1 do ionski 2
extension Collection { public func map(_ transform: (Self.Iterator.Element) throws -> T) rethrows -> [T] { } }
Kot sem že omenil, nam razširitve protokolov omogočajo dodajanje privzetih izvedb nekaterih metod in dodajanje novih izvedb metod. Kakšna pa je razlika med tema dvema značilnostma? Vrnimo se k upravljavcu napak in ugotovimo.
protocol ErrorHandler { func handle(error: Error) } extension ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } } struct Handler: ErrorHandler { func handle(error: Error) { fatalError('Unexpected error occurred') } } enum ApplicationError: Error { case other } let handler: Handler = Handler() handler.handle(error: ApplicationError.other)
Rezultat je usodna napaka.
Zdaj odstranite handle(error: Error)
izjava metode iz protokola.
protocol ErrorHandler { }
Rezultat je enak: usodna napaka.
Ali to pomeni, da ni razlike med dodajanjem privzete izvedbe metode protokola in dodajanjem nove izvedbe metode protokolu?
Ne! Razlika obstaja in to lahko vidite, če spremenite vrsto spremenljivke handler
od Handler
do ErrorHandler
.
let handler: ErrorHandler = Handler()
Zdaj je izhod v konzolo: Operacije ni bilo mogoče dokončati. (Napaka ApplicationError 0.)
Če pa protokolu vrnemo deklaracijsko metodo ročaja (error: Error), se bo rezultat spremenil nazaj v usodno napako.
protocol ErrorHandler { func handle(error: Error) }
Oglejmo si vrstni red dogajanja v posameznem primeru.
Ko v protokolu obstaja izjava metode:
Protokol označuje handle(error: Error)
metoda in zagotavlja privzeto izvedbo. Metoda je razveljavljena v Handler
izvajanje. Torej se med izvajanjem prikliče pravilna izvedba metode, ne glede na vrsto spremenljivke.
Če izjava metode v protokolu ne obstaja:
Ker metoda ni deklarirana v protokolu, je tip ne more preglasiti. Zato je izvedba klicane metode odvisna od vrste spremenljivke.
Če je spremenljivka tipa Handler
, se pokliče izvedba metode iz tipa. Če je spremenljivka tipa ErrorHandler
, se pokliče izvedba metode iz razširitve protokola.
V tem članku smo pokazali nekaj moči razširitev protokola v Swiftu.
Za razliko od drugih programskih jezikov z vmesniki, Swift ne omejuje protokolov z nepotrebnimi omejitvami. Swift se ukvarja s splošnimi domislicami teh programskih jezikov, tako da razvijalcu omogoča, da po potrebi razreši dvoumnosti.
S protokoli Swift in razširitvami protokolov je koda, ki jo napišete, lahko tako izrazita kot večina dinamičnih programskih jezikov in je v času prevajanja še vedno varna za tip. To vam omogoča, da zagotovite ponovno uporabo in vzdrževanje kode ter da bolj samozavestno spreminjate kodno bazo aplikacije Swift.
Upamo, da vam bo ta članek koristen in pozdravljamo kakršne koli povratne informacije ali nadaljnja spoznanja.