koncept řízení přístupu nám umožňuje omezit přístup typů, funkcí a dalších deklarací jiným kódem. Swift nabízí pět různých úrovní řízení přístupu a jejich plné využití může být zásadní pro psaní programů, které mají jasně oddělené obavy a robustní strukturu.

když definujeme jakýkoli nový typ, vlastnost nebo funkci ve Swiftu, bude mít ve výchozím nastavení úroveň přístupu internal. To znamená, že bude viditelný pro všechny ostatní kódy, které žijí ve stejném modulu — například aplikace, rozšíření systému, rámec nebo balíček Swift.

jako příklad Řekněme, že vytváříme nákupní aplikaci a že jsme definovali třídu nazvanou PriceCalculator, která nám umožňuje vypočítat celkovou cenu za řadu produktů:

protože v současné době neurčujeme žádnou explicitní úroveň přístupu, bude naše třída PriceCalculator (a její metoda calculatePrice) přístupná odkudkoli v naší aplikaci. Pokud však chceme sdílet naši novou třídu s dalšími moduly (můžeme ji například implementovat v rámci, který sdílíme mezi naší hlavní aplikací a rozšířením nebo doprovodnou aplikací Apple Watch), pak ji budeme muset vytvořit public, aby byla viditelná v těchto vnějších kontextech:

výše uvedená změna však nestačí. I když jsme nyní schopni najít naši třídu mimo modul, ve kterém je definována, nemůžeme vytvořit žádné instance – protože její (implicitní) inicializátor je, stejně jako jakýkoli jiný kód, ve výchozím nastavení internal. Chcete-li to opravit, definujme inicializátor public, který necháme prázdný, protože v něm není žádná skutečná práce:

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

nyní jsme schopni najít, Inicializovat a volat náš PriceCalculator uvnitř i vně jeho modulu-fantastický. Ale řekněme, že se také snažíme podtřídu, abychom ji upravili nebo přidali nové funkce. I když je to v současné době možné v rámci vlastního modulu, je to opět něco, co je mimo něj zabráněno.

abychom to změnili, budeme muset použít v současné době nejotevřenější úroveň řízení přístupu Swift, která je vhodně pojmenována open:

open class PriceCalculator { ...}

s výše uvedenou změnou na místě můžeme nyní vytvářet vlastní podtřídy PriceCalculator kdekoli — které mohou mít nové inicializátory, nové vlastnosti a nové metody. Zde je návod, jak to můžeme použít k implementaci DiscountedPriceCalculator, což nám umožňuje použít daný discount pro všechny cenové výpočty:

výše definujeme zcela novou metodu výpočtu ceny, ale pravděpodobně by bylo mnohem vhodnější přepsat a upravit stávající metodu calculatePrice, kterou jsme zdědili z naší základní třídy. Tímto způsobem by nedošlo k záměně, kterou metodu zavolat, a mohli bychom udržet naše dvě třídy konzistentní.

abychom to mohli udělat, musíme znovu označit původní prohlášení-tentokrát naše calculatePrice prohlášení o metodě-jako open:

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

s výše uvedeným na místě, můžeme nyní volně přepsat calculatePrice, spíše než museli vytvořit samostatnou metodu:

takže to jsou internal, public a open – které se používají k postupnému otevření prohlášení pro veřejné použití a úpravy. Ale můžeme samozřejmě také jít opačným směrem a skrýt části našeho kódu před objevením a použitím. Zpočátku se může zdát sporné, jaká je hodnota, ale může nám to opravdu pomoci učinit naše API mnohem užším a soustředěnějším — což zase může usnadnit pochopení, testování a použití.

pojďme tedy nyní až na druhou stranu spektra přístupové úrovně a podívejme se na nejvíce restriktivní úroveň – private. Jakýkoli typ, vlastnost nebo metoda, která je označena jako private, budou viditelné pouze v rámci svého vlastního typu (který také zahrnuje přípony tohoto typu definované ve stejném souboru).

vše, co by mělo být považováno za soukromý implementační detail daného typu, by mělo být pravděpodobně označeno jako private. Například Naše cenová kalkulačka discount vlastnost z dřívějška byla skutečně určena pouze k použití ve své vlastní třídě — tak pojďme do toho a učiníme tuto nemovitost soukromou:

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

naše předchozí implementace bude i nadále fungovat přesně stejným způsobem jako dříve, protože discount zůstane zcela viditelný v naší třídě DiscountedPriceCalculator. Pokud bychom však chtěli tuto viditelnost mírně rozšířit tak, aby zahrnovala i další typy definované ve stejném souboru, museli bychom použít fileprivate – což dělá přesně to, co zní, udržuje prohlášení soukromé v souboru, ve kterém je definováno:

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

s výše uvedenou změnou na místě nyní můžeme přistupovat k naší vlastnosti discount ze souvisejícího kódu definovaného ve stejném souboru — jako je toto rozšíření na UIAlertController, které nám umožňuje snadno zobrazit popis ceny pro řadu produktů v rámci upozornění:

pokud jde o bezplatné funkce, typy a rozšíření, private a fileprivate fungují přesně stejně. Liší se pouze při použití deklarací, které jsou definovány v rámci typu.

abychom to shrnuli, jedná se o pět úrovní řízení přístupu, které Swift v současné době nabízí:

  • private udržuje vlastnost nebo funkci soukromou v rámci svého uzavíracího typu, včetně všech přípon tohoto typu, které jsou definovány ve stejném souboru. Při aplikaci na typ, funkci nebo rozšíření nejvyšší úrovně se chová stejným způsobem jako fileprivate.
  • fileprivate zviditelní deklaraci v celém souboru, ve kterém je definována, a zároveň ji skryje před všemi ostatními kódy.
  • internal je výchozí úroveň přístupu a zviditelňuje deklaraci v celém modulu, ve kterém je definována.
  • public odhaluje funkci, typ, rozšíření nebo vlastnost mimo svůj modul.
  • open umožňuje podtřídu třídy a přepsání funkce nebo vlastnosti mimo její modul.

obecně je často nejlepší začít s nejpřísnější úrovní přístupu, kterou může dané prohlášení prakticky mít, a v případě potřeby později otevřít věci. Tímto způsobem omezujeme možnosti interakce mezi našimi různými typy a funkcemi, což se může zpočátku zdát jako špatná věc, ale často je skutečně nezbytné pro vybudování udržovatelných a dobře strukturovaných systémů.

Díky za přečtení! 🚀

(Všimněte si, že tento článek nešel do modifikátorů přístupu specifických pro mutace, například private(set). Ty se budou v budoucnu týkat dalšího základního článku.)

podpora Swift by Sundell kontrolou tohoto sponzora:

Instabug: Vyřešte chyby, pády a další problémy mnohem rychleji pomocí podrobných Stop zásobníku, síťových protokolů a událostí uživatelského rozhraní, které Instabug automaticky připojí ke každé zprávě o chybě. Používá mě i tisíce vývojových týmů iOS po celém světě. Vyzkoušejte to zdarma a integrujte jej pouze s jedním řádkem kódu.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.