Access Level in Swift

Welche es gibt und wie ich sie persönlich in Projekten einsetze

Die Access Level in Swift steuern seit jeher die Berechtigungen, mit denen sich auf die Code-Fragmente eines Projekts zugreifen lässt. Access Level regeln so unter anderem, ob beispielsweise Properties nur innerhalb eines Typs angesprochen werden können oder auch direkt von Instanzen jenes Typs auslesbar sind. Das nachfolgende Listing skizziert einmal dieses Szenario:

struct Person {
    internal var name: String
    private var address: String?

    init(name: String) {
        self.name = name
    }

    internal func printAddress() {
        guard let address else {
            return
        }
        print(address)
    }
}

var me = Person(name: "Thomas Sillmann")

print(me.name)
// Thomas Sillmann

print(me.address) // Fehler: Kein Zugriff auf address möglich.

Die Eigenschaft name der Structure Person besitzt den Access Level internal. Innerhalb eines Projekts kann sie so problemlos von Instanzen der Structure angesprochen und ausgelesen werden. Anders verhält es sich mit address. address ist als private deklariert und steht so ausschließlich innerhalb der Structure Person selbst zur Verfügung (wie in der Implementierung der Methode printAddress() zu sehen). Ein Zugriff von außen über eine Person-Instanz ist nicht möglich (wie der print-Aufruf am Ende des Listings beispielhaft demonstriert).

Verfügbare Access Level

Nach dieser kleinen Einführung in das Grundprinzip der Access Level stelle ich euch nun einmal die verschiedenen Level und ihre Funktionsweise kurz vor:

  • private: Das restriktivste Access Level. Als private gekennzeichnete Elemente können nur innerhalb des Scopes angesprochen und verwendet werden, in dem sie deklariert sind. Die Property name aus dem vorangegangenen Listing steht so nur innerhalb der Structure Person zur Verfügung.
  • fileprivate: Verhält sich ähnlich wie private, weitet den Zugriff aber auf die zugrundeliegende Datei aus. Wäre name als fileprivate gekennzeichnet und ist das print-Statement am Ende Teil derselben Swift-Datei, in der auch die Structure Person deklariert ist, wäre so ein Zugriff auf name möglich. Aus anderen Dateien heraus würde name jedoch dann nicht zur Verfügung stehen.
  • internal: Dieses Access Level ist der Standard und kommt immer automatisch zum Einsatz, wenn kein anderes Access Level explizit angegeben ist. Eine explizite Verwendung von internal, so wie sie bei der Deklaration der name-Property zum Einsatz kam, ist nicht notwendig, aber möglich.
    Mittels internal legt man fest, dass das zugehörige Element innerhalb eines Projekts bzw. Moduls zur Verfügung steht. Entwickelt man eine App, stehen internal-Elemente entsprechend innerhalb des gesamten App-Projekts zur Verfügung (sofern man verschiedene Projektteile nicht in separate und unabhängige Module auslagert).
  • public: Dieses Access Level ist typischerweise dann relevant, wenn man beispielsweise ein Framework entwickelt, das als Modul in andere Projekte eingebunden werden soll. Die als public gekennzeichneten Elemente stellen dann die öffentliche API des Moduls dar, die aus anderen Projekten, die das Modul einbinden, angesprochen werden kann. Würdet ihr ein Framework entwickeln, dass nur die erstgenannten Access Level private, fileprivate und internal verwendet, wäre der gesamte Code nicht verwendbar, würde er in Form eines Moduls in einem anderen Projekt eingebunden werden. Es braucht also public um festzulegen, welche Teile eines Moduls aus anderen Projekten heraus nutzbar sind.
    Wichtig hierbei: Als public gekennzeichnete Klassen, Properties und Methoden können zwar in anderen Modulen verwendet, aber nicht überschrieben werden. Es lassen sich demnach keine Subklassen dieser Elemente erzeugen oder Properties und Methoden überschreiben.
  • open: open stellt das am wenigsten restriktive Access Level dar und verhält sich im Grunde ähnlich wie public, es ist also bei der Deklaration der öffentlichen API von Modulen relevant. Im Gegensatz zu public ermöglicht es open jedoch, Subklassen zu erstellen und Properties sowie Methoden zu überschreiben. Setzt man open ein, muss man also bedanken, dass Nutzer die zugrundeliegende Funktionalität des eigenen Codes erweitern bzw. verändern können. Entsprechend sollte man open nur dann verwenden, wenn solch ein Vorgehen explizit gewünscht ist und nicht zu Problemen bei der sonstigen Funktionalität des zugrundeliegenden Moduls führen kann.

Mein persönlicher Einsatz der Access Level

open und public spielen in meinem persönlichen Entwickler-Alltag so gut wie gar keine Rolle. Das liegt daran, da ich nur sehr selten an Frameworks oder Modulen außerhalb eines spezifischen App-Projekts arbeite. Der Großteil meiner Arbeit findet innerhalb solcher in sich geschlossenen App-Projekte statt, für die open und public schlicht nicht relevant sind. Daher klammere ich diese beiden Access Level an dieser Stelle aus.

Von den übrigen drei Access Leveln nutze ich ausschließlich zwei: internal und private.

internal dürfte nicht wenig überraschend sein. Dieses Standard-Access Level ist zwingend notwendig, um innerhalb eines App-Projekts mit all den verschiedenen Typen, Eigenschaften und Funktionen kommunizieren zu können, die für das Projekt notwendig sind. Für alle Interaktionen von Instanzen untereinander nutze ich so internal und regle damit die Funktionsweise von Apps.

Das andere Extrem stellt private dar. Bei der Deklaration von Typen und deren Properties und Methoden kommt es sehr häufig vor, das einzelne Eigenschaften nur für die Implementierung jenes Typs bestimmt sind und von außen nicht zugänglich sein müssen oder sollen. Genau für diese Zwecke nutze ich private, und das sehr exzessiv. Im Endeffekt gilt: Was nicht internal zu sein braucht, wird private.

Und was ist mit fileprivate? Tatsächlich gab es bisher kaum Anwendungsfälle, in denen fileprivate für mich relevant gewesen wäre. Das hängt sicherlich auch damit zusammen, dass ich meinen Code in der Regel umfangreich auf mehrere Swift-Dateien verteile. So hat jeder Typ meist seine eigene Swift-Datei, Extensions oftmals ebenso. Zugriffe mittels fileprivate dann auf eine spezifische Datei zu begrenzen, bringt in diesen Szenarien nichts und ist funktional identisch zur private-Deklaration (die in meinem Fall dann zum Einsatz käme).


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert