begreppet åtkomstkontroll gör det möjligt för oss att begränsa hur typer, funktioner och andra deklarationer kan nås med annan kod. Swift erbjuder fem olika nivåer av åtkomstkontroll, och att utnyttja dem fullt ut kan vara avgörande för att skriva program som har tydligt separerade problem och en robust struktur.

när vi definierar någon ny typ, egenskap eller funktion i Swift, kommer den att ha åtkomstnivån internal som standard. Det betyder att det kommer att vara synligt för all annan kod som bor inom samma modul — till exempel en app, ett systemtillägg, ett ramverk eller ett Swift-paket.

låt oss till exempel säga att vi bygger en shoppingapp och att vi har definierat en klass som heter PriceCalculator som låter oss beräkna det totala priset för en rad produkter:

eftersom vi för närvarande inte anger någon explicit åtkomstnivå kommer vår PriceCalculator – klass (och dess calculatePrice – metod) att vara tillgänglig var som helst i vår app. Men om vi vill dela vår nya klass med andra moduler (vi kan till exempel implementera den inom ett ramverk som vi delar mellan vår huvudapp och ett tillägg eller en medföljande Apple Watch-app), måste vi göra det public för att det ska vara synligt inom dessa externa sammanhang:

ovanstående ändring är dock inte tillräckligt. Medan vi nu kan hitta vår klass utanför modulen som den definieras i, kan vi inte skapa några instanser av den — eftersom dess (implicita) initializer är, precis som någon annan kod, internal som standard. För att fixa det, låt oss definiera en public initializer, som vi lämnar tomt eftersom det inte finns något verkligt arbete att göra inom det:

public class PriceCalculator { public init() {} ...}

Vi kan nu hitta, initiera och ringa vår PriceCalculator både inom och utanför modulen — fantastiskt. Men låt oss nu säga att vi också vill underklassa det för att ändra det eller lägga till ny funktionalitet till den. Medan det för närvarande är möjligt inom sin egen modul, är det igen något som förhindras utanför det.

för att ändra det måste vi använda Swifts för närvarande mest öppna nivå av åtkomstkontroll, som är lämpligt namngiven open:

open class PriceCalculator { ...}

med ovanstående förändring på plats kan vi nu skapa anpassade underklasser av PriceCalculator var som helst-som kan ha nya initialisatorer, nya egenskaper och nya metoder. Så här kan vi använda det för att implementera en DiscountedPriceCalculator , som låter oss tillämpa en given discount på alla prisberäkningar:

ovan definierar vi en helt ny prisberäkningsmetod, men det skulle utan tvekan vara mycket lämpligare att åsidosätta och ändra den befintliga calculatePrice – metoden som vi ärvde från vår basklass istället. På så sätt skulle det inte finnas någon förvirring kring vilken metod vi skulle ringa, och vi kunde hålla våra två klasser konsekventa.

för att kunna göra det måste vi återigen markera den ursprungliga deklarationen-den här gången vår calculatePrice metoddeklaration-som open:

open class PriceCalculator { public init() {} open func calculatePrice(for products: ) -> Int { ... }}

med ovanstående på plats kan vi nu fritt åsidosätta calculatePrice, snarare än att behöva skapa en separat metod:

så det är internal, public och open — som används för att gradvis öppna en deklaration för allmän användning och modifiering. Men vi kan naturligtvis också gå åt andra hållet, och dölja delar av vår kod från att upptäckas och användas. Först kan det tyckas tvivelaktigt vad värdet är att göra det, men det kan verkligen hjälpa oss att göra vårt API mycket smalare och fokuserat — vilket i sin tur kan göra det lättare att förstå, testa och använda.

så låt oss nu gå hela vägen till andra sidan åtkomstnivåspektrumet och ta en titt på den mest restriktiva nivån — private. Vilken typ, egenskap eller metod som är markerad som private kommer bara att vara synlig inom sin egen typ (som även inkluderar tillägg på den typen som definieras i samma fil).

allt som bör betraktas som en privat implementeringsdetalj av en viss typ bör utan tvekan markeras som private. Till exempel var vår priskalkylatorns discount egendom från tidigare egentligen bara avsedd att användas inom sin egen klass – så låt oss fortsätta och göra den egendomen privat:

class DiscountedPriceCalculator: PriceCalculator { private let discount: Int ...}

vår tidigare implementering kommer att fortsätta att fungera exakt på samma sätt som tidigare, eftersom discount kommer att förbli helt synlig inom vår DiscountedPriceCalculator – klass. Men om vi ville förlänga den synligheten något för att även inkludera andra typer definierade i samma fil, måste vi använda fileprivate – vilket gör exakt vad det låter som, det håller en deklaration privat i filen som den definieras i:

class DiscountedPriceCalculator: PriceCalculator { fileprivate let discount: Int ...}

med ovanstående ändring på plats kan vi nu komma åt vår discount — egenskap från relaterad kod definierad i samma fil-till exempel denna tillägg på UIAlertController som låter oss enkelt visa en prisbeskrivning för en rad produkter inom en varning:

när det gäller fria funktioner, typer och tillägg, private och fileprivate agera exakt samma. De är bara annorlunda när de tillämpas på deklarationer som definieras inom en typ.

så för att sammanfatta är det de fem nivåerna av åtkomstkontroll som Swift för närvarande erbjuder:

  • private håller en egenskap eller funktion privat inom sin omslutande typ, inklusive eventuella tillägg på den typen som definieras i samma fil. När den appliceras på en toppnivåtyp, funktion eller förlängning fungerar den på samma sätt som fileprivate.
  • fileprivate gör en deklaration synlig i hela filen som den definieras i, samtidigt som den döljs från all annan kod.
  • internal är standardåtkomstnivån och gör en deklaration synlig i hela modulen som den definieras i.
  • public avslöjar en funktion, typ, förlängning eller egenskap utanför modulen.
  • open gör det möjligt att underklassa en klass och att åsidosätta en funktion eller egenskap utanför modulen.

i allmänhet är det ofta bäst att börja med den mest restriktiva åtkomstnivån som en viss deklaration praktiskt taget kan ha och sedan öppna saker senare om det behövs. På så sätt begränsar vi möjligheterna till interaktion mellan våra olika typer och funktioner, vilket i början kan verka som en dålig sak, men är ofta verkligen viktigt för att bygga underhållbara och välstrukturerade system.

Tack för att du läste!

(Observera att den här artikeln inte gick in i mutationsspecifika åtkomstmodifierare, till exempel private(set). De kommer att omfattas av en annan grundläggande artikel i framtiden.)

stöd Swift av Sundell genom att kolla in denna sponsor:

Instabug: Lösa buggar, krascher och andra frågor mycket snabbare med hjälp av detaljerade stack spår, nätverksloggar och UI händelser som Instabug automatiskt fäster varje felrapport. Används både av mig och tusentals iOS-utvecklingsteam runt om i världen. Prova det gratis och integrera det med bara en enda kodrad.

Lämna ett svar

Din e-postadress kommer inte publiceras.