het concept Toegangscontrole stelt ons in staat om te beperken hoe typen, functies en andere declaraties toegankelijk zijn met andere code. Swift biedt vijf verschillende niveaus van toegangscontrole, en het volledig gebruik ervan kan cruciaal zijn om programma ‘ s te schrijven die duidelijk gescheiden zorgen en een robuuste structuur hebben.

wanneer we een nieuw type, eigenschap of functie definiëren in Swift, zal het standaard internal toegangsniveau hebben. Dat betekent dat het zichtbaar is voor alle andere code die binnen dezelfde module leeft — zoals een app, een systeemextensie, een framework of een Swift-pakket.

als voorbeeld, laten we zeggen dat we een shopping app bouwen, en dat we een klasse genaamd PriceCalculator hebben gedefinieerd waarmee we de totale prijs voor een reeks producten kunnen berekenen:

omdat we momenteel geen expliciet toegangsniveau specificeren, zal onze PriceCalculator klasse (en de calculatePrice methode) overal binnen onze app toegankelijk zijn. Als we onze nieuwe klasse echter willen delen met andere modules (we kunnen het bijvoorbeeld implementeren binnen een raamwerk dat we delen tussen onze hoofd-app en een extensie, of een bijbehorende Apple Watch-app), dan moeten we het public maken om zichtbaar te zijn binnen die externe contexten:

bovenstaande wijziging is echter niet voldoende. Hoewel we nu in staat zijn om onze klasse te vinden buiten de module waarin het is gedefinieerd, kunnen we er geen instanties van maken — omdat de (impliciete) initializer standaard internal is, net als elke andere code. Om dat op te lossen, laten we een public initializer definiëren, die we leeg laten omdat er geen werk in zit.:

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

we zijn nu in staat om onze PriceCalculator zowel binnen als buiten de module te vinden, te initialiseren en te bellen — fantastisch. Maar laten we nu zeggen dat we het ook willen onderklassen om het te wijzigen, of om er nieuwe functionaliteit aan toe te voegen. Hoewel dat momenteel mogelijk is binnen zijn eigen module, is het weer iets dat buiten wordt voorkomen.

om dat te veranderen, moeten we gebruik maken van Swift ‘ s momenteel meest open niveau van toegangscontrole, die de juiste naam heeft open:

open class PriceCalculator { ...}

met de bovenstaande verandering kunnen we nu aangepaste subklassen van PriceCalculator overal maken-die nieuwe initializers, nieuwe eigenschappen en nieuwe methoden kunnen hebben. Hier is hoe we dat kunnen gebruiken om een DiscountedPriceCalculator te implementeren, waarmee we een gegeven discount kunnen toepassen op alle prijsberekeningen:

hierboven definiëren we een gloednieuwe prijsberekeningsmethode, maar het zou veel geschikter zijn om de bestaande calculatePrice methode die we geërfd hebben van onze basisklasse te overschrijven en te wijzigen. Op die manier zou er geen verwarring zijn over welke methode te noemen, en we zouden onze twee klassen consistent kunnen houden.

om dat te kunnen doen, moeten we opnieuw de oorspronkelijke declaratie — deze keer onze declaratie calculatePrice methode-markeren als open:

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

met het bovenstaande op zijn plaats, kunnen we nu vrij overschrijven calculatePrice, in plaats van het maken van een aparte methode:

dus dat is internal, public en open – die worden gebruikt om geleidelijk een verklaring te openen voor publiek gebruik en wijziging. Maar we kunnen natuurlijk ook de andere kant op gaan, en delen van onze code verbergen om ontdekt en gebruikt te worden. Op het eerste, het lijkt misschien twijfelachtig wat de waarde is in het doen van dat, maar het kan ons echt helpen om onze API veel smal en gericht — die op zijn beurt kan maken het gemakkelijker te begrijpen, testen, en gebruik.

dus laten we nu helemaal naar de andere kant van het toegangsniveauspectrum gaan, en kijken naar het meest restrictieve niveau — private. Elk type, eigenschap of methode die gemarkeerd is als private zal alleen zichtbaar zijn binnen zijn eigen type (dat ook extensies bevat op dat type dat in hetzelfde bestand is gedefinieerd).

alles dat als een particulier implementatiedetail van een bepaald type moet worden beschouwd, moet aantoonbaar worden gemarkeerd als private. Bijvoorbeeld, onze prijs calculator ‘ s discount property van vroeger was eigenlijk alleen bedoeld om te worden gebruikt binnen zijn eigen klasse – dus laten we gaan en maken dat property private:

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

onze vorige implementatie zal op dezelfde manier blijven werken als voorheen, aangezien discount volledig zichtbaar blijft binnen onze DiscountedPriceCalculator klasse. Echter, als we die zichtbaarheid enigszins willen uitbreiden om ook andere types in hetzelfde bestand op te nemen, moeten we fileprivate gebruiken-wat precies doet wat het klinkt, het houdt een verklaring privé binnen het bestand waarin het is gedefinieerd:

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

met de bovenstaande verandering in plaats, kunnen we nu toegang krijgen tot onze discount eigenschap van gerelateerde code gedefinieerd in hetzelfde bestand — zoals deze extensie op UIAlertController die ons gemakkelijk een prijsbeschrijving laat zien voor een reeks producten binnen een waarschuwing:

als het gaat om vrije functies, types en extensies, private en fileprivate handelen precies hetzelfde. Ze verschillen alleen als ze worden toegepast op verklaringen die binnen een type zijn gedefinieerd.

Kortom, dit zijn de vijf niveaus van toegangscontrole die Swift momenteel aanbiedt:

  • private houdt een eigenschap of functie privé binnen het ingesloten type, inclusief eventuele uitbreidingen op dat type die in hetzelfde bestand zijn gedefinieerd. Wanneer toegepast op een top-level type, functie of extensie, werkt het op dezelfde manier als fileprivate.
  • fileprivate maakt een declaratie zichtbaar in het gehele bestand waarin het is gedefinieerd, terwijl het wordt verborgen voor alle andere code.
  • internal is het Standaard toegangsniveau en maakt een declaratie zichtbaar binnen de gehele module waarin het is gedefinieerd.
  • public toont een functie, type, extensie of eigenschap buiten de module.
  • open maakt het mogelijk om een klasse te subklassen en een functie of eigenschap te overschrijven buiten de module.

in het algemeen is het vaak het beste om te beginnen met het meest restrictieve toegangsniveau dat een bepaalde declaratie in de praktijk kan hebben, en vervolgens, indien nodig, dingen later open te stellen. Op die manier beperken we de mogelijkheden voor interactie tussen onze verschillende types en functies, wat op het eerste gezicht misschien slecht lijkt, maar vaak echt essentieel is om onderhoudbare en goed gestructureerde systemen te bouwen.

Bedankt voor het lezen! 🚀

(merk op dat dit artikel niet ging over mutatie-specifieke toegangsmodifiers, zoals private(set). Die zullen in de toekomst worden behandeld door een ander basisartikel.)

Support Swift by Sundell door deze sponsor uit te checken:

Instabug: Los bugs, crashes en andere problemen veel sneller op met behulp van de gedetailleerde stack traces, netwerklogs en UI-gebeurtenissen die Instabug automatisch aan elk bugrapport hecht. Gebruikt door mij en duizenden iOS-ontwikkelingsteams over de hele wereld. Probeer het gratis en integreer het met slechts een enkele regel code.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.