Link Search Menu Expand Document

Контроль доступу

Контроль доступу обмежує доступ до частин вашого коду із коду в інших вихідних файлах та модулях. Цей механізм дозволяє приховувати деталі реалізації вашого коду, та визначати доречний інтерфейс, через який слід звертатись до вашого коду та використовувати його.

Конкретний рівень доступу можна присвоїти окремим типам (класам, структурам та перечисленням), так само як і властивостям, методам, ініціалізаторам, та індексам, що належать до цих типів. Протоколи також можна обмежити до певного контексту, а також глобальні константи, змінні та функції.

Окрім пропонування різних рівнів контролю доступу, Swift зменшує потребу вказувати рівень контролю доступу явно, надаючи рівні доступу за замовчанням для типових сценаріїв. Дійсно: якщо ви пишете простий монолітний додаток з єдиним таргетом, вам узагалі не обов’язково вказувати рівні доступу явно.

Примітка

Різні частини коду, що можуть мати рівень доступу (властивості, типи, функції, і так далі) будуть називатись у даному розділі “сутностями” заради лаконічності.

Модулі та вихідні файли

Модель контролю доступу у Swift базується на концепції модулів та вихідних файлів.

Модуль – це окрема одиниця дистрибуції коду: фреймворк чи додаток, що будується і поставляється як окрема одиниця, що може імпортуватись іншим модулем за допомогою ключового слова import.

Кожен таргет збірки (як, наприклад, додаток чи фреймворк) у Xcode вважається окремим модулем у Swift. Якщо згрупувати разом частини коду вашого додатку в окремий фреймворк – наприклад, щоб інкапсулювати та повторно використовувати цей код у кількох різних додатках – тоді все, що буде оголошено всередині цього фреймворку, буде частиною окремого модуля при імпортуванні та використанні всередині додатку, чи при використанні в іншому фреймворку.

Вихідним файлом є окремий файл із вихідним кодом на Swift всередині модуля (фактично, окремий файл всередині додатку чи фреймворку). Хоч загальноприйнятим вважається оголошувати кожен тип в окремому файлі, в одному вихідному файлі можуть міститись визначення кількох типів, функцій і так далі.

Рівні доступу

У Swift є п’яті різних рівнів доступу до сутностей всередині коду. Ці рівні доступу є відносними до вихідного файлу, в якому оголошено сутність, і також відносними до модуля, до якого належить файл із вихідним кодом.

  • Відкритий доступ (open) та публічний доступ (public) дозволяють сутностям використовуватись у будь-якому вихідному файлі як у модулі, де вони оголошені, так і у будь-якому іншому модулі, що імпортує модуль, в якому вони оголошені. Як правило, відкритий та публічний доступ використовуються при визначенні публічного інтерфейсу для фреймворку. Різниця між ними описана далі.
  • Внутрішній доступ (internal) дозволяє сутностям використовуватись у будь-якому вихідному файлі в модулі, де вони оголошуються, але забороняє їм використовуватись зовні цього модуля. Зазвичай внутрішній доступ використовується для визначення внутрішньої структури додатку чи фреймворку.
  • Файлоприватний доступ (fileprivate) забороняє використовувати сутності зовні файлу, де вони оголошені. Файлоприватний доступ використовується для приховання деталей реалізації певної частини функціональності, дозволяючи цим деталям використовуватись в рамках одного файлу.
  • Приватний доступ (private) забороняє використовувати сутність за межами довколишнього оголошення та розширень цього оголошення, що знаходяться в тому ж самому файлі. Приватний доступ використовується для приховання деталей реалізації конкретної частини функціональності, коли ці деталі використовуються лише всередині окремого оголошення.

Відкритий доступ є найвищим (найменш обмежуючим) рівнем доступу, а приватний доступ є найнижчим (найбільш обмежуючим) рівнем доступу.

Відкритий доступ застосовується лише до класів та членів класу, і відрізняється від публічного доступу наступним чином:

  • Класи з публічним доступом, або більш строгим рівнем доступу, можуть бути успадкованими лише всередині модуля, де вони оголошені.
  • Члени класу із публічним доступом, або більш строгим рівнем доступу, можуть бути заміщеними лише всередині модуля, де їх оголошено.
  • Відкриті класи можуть бути успадкованими як всередині модуля, де їх оголошено, так і зовні цього модуля, у будь-якому модулі, що імпортує модуль, де їх оголошено.
  • Члени відкритих класів можуть бути заміщеними у класах-нащадках як всередині модуля, де їх оголошено, так і всередині будь-якого модуля, що імпортує модуль, де їх оголошено.

Якщо клас є відкритим, це явним чином вказує на те, що автор врахував вплив коду з інших модулів, котрий використовує даний клас як батьківський клас, і що автор спроєктував код всередині цього класу відповідним чином.

Керівний принцип рівнів доступу

Рівні доступу у Swift підкоряються загальному керівному принципу: Жодна сутність не може бути оголошеною в контексті іншої сутності, що має нижчий (більш обмежуючий) рівень доступу.

Наприклад:

  • Публічна змінна може не може оголошуватись із внутрішнім, файлоприватним чи приватним типом, оскільки цей тип може бути доступним не у всіх місцях, де може використовуватись публічна змінна.
  • Функція не може мати вищого рівня доступу, аніж типи її параметрів та тип, котрий вона повертає, оскільки функція може використовуватись у ситуаціях, коли її складові типи є недоступними для довколишнього коду.

Конкретні наслідки цього керівного принципу у різних аспектах мови детально розкриті нижче.

Рівні доступу за замовчанням

Усі сутності у коді (крім небагатьох виключень, які описані в даному розділі) мають внутрішній рівень доступу за замовчанням, якщо явно не вказано інший рівень доступу. У результаті, в більшості випадків не потрібно вказувати явно рівень доступу у вашому коді.

Рівні доступу у додатках з єдиним таргетом

При написанні простого додатка з єдиним таргетом, код цього додатку є як правило самодостатнім, і він не повинен бути доступним зовні модуля додатку. Внутрішній рівень доступу за замовчанням як раз відповідає цій вимозі. Таким чином, при написанні додатку не обов’язково вказувати власний рівень доступу. Втім, деякі частини коду може бути бажано помічати файлоприватними чи приватними, щоб приховати деталі їх реалізації від іншого коду всередині модуля додатку.

Рівні доступу у фреймворках

При розробці фреймворку, слід помічати публічний інтерфейс цього фреймворку відкритим чи публічним, щоб робити його видимим в інших модулях, що імпортуються даний фреймворк. Публічний інтерфейс є інтерфейсом програмування додатків (або API, від application programming interface) для даного фреймворку.

Примітка

Будь-які деталі внутрішньої реалізації вашого фреймворка можуть мати внутрішній рівень доступу за замовчанням, або бути поміченими приватними чи файлоприватними, якщо потрібно приховати їх від інших частин внутрішнього коду вашого фреймворка. Сутності повинні бути відкритими або публічними тільки у тому випадку, якщо вони повинні бути частною API вашого фреймворка.

Рівні доступу для таргетів юніт-тестів

При написанні додатку із таргетом юніт-тестів, код у вашому додатку повинен бути доступним для модуля юніт-тестів, щоб його можна було протестувати. За замовчанням, лише відкриті та публічні сутності можуть бути доступними в інших модулях. Однак, таргет юніт-тестів може мати доступ до внутрішньої сутності, якщо помітити інструкцію імпортування модуля додатку import за допомогою атрибута @testable, та скомпілювати модуль додатку з увімкненим режимом тестування (за допомогою налаштування компіляції ENABLE_TESTABILITY).

Синтаксис контролю доступу

Рівень доступу сутності визначається за допомогою одного з модифікаторів open, public, internal, fileprivate, чи private перед оголошенням сутності:

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

Якщо не вказано інше, рівнем доступу за замовчанням є внутрішній, як описано вище в Рівні доступу за замовчанням. Це означає, що SomeInternalClass та someInternalConstant можуть записуватись без явного модифікатора рівня доступу, і все ще матимуть внутрішній рівень доступу:

class SomeInternalClass {}              // неявно внутрішній (internal)
let someInternalConstant = 0            // неявно внутрішній (internal)

Власні типи

Якщо вам потрібно визначити явний рівень доступу для вашого власного типу, слід робити це в момент визначення самого типу. Новий тип після цього може використовуватись всюди, де це дозволяє рівень доступу. Наприклад, якщо визначено файлоприватний клас, його можна використовувати як тип властивості, чи як тип параметру функції, чи як тип, що повертається функцією, але лише у вихідному файлі, в якому визначено цей файлоприватний клас.

Рівень доступу типу також впливає на рівень доступу за замовчанням членів цього типу (його властивостей, методів, ініціалізаторів та індексів). Якщо визначати рівень доступу до типу як приватний чи файлоприватний, рівнем доступу його членів буде також приватним чи файлоприватним. Якщо визначити рівень доступу до типу як внутрішній чи публічний (або використати внутрішній рівень доступу за замовчанням, не вказавши тип доступу явно), рівнем доступу членів типу за замовчанням буде внутрішній.

Важливо

Публічний тип має за замовчанням внутрішні члени, а не публічні. Якщо потрібно, щоб член типу був публічним, слід позначити його таким явно. Ця вимога гарантує, що публічний API типу є чимось що автор усвідомлено опублікував, і запобігає помилковому включенню внутрішніх робочих типів у публічний API.

public class SomePublicClass {                   // явно публічниий клас
    public var somePublicProperty = 0            // явно публічниий член класу
    var someInternalProperty = 0                 // неявно внутрішній член класу
    fileprivate func someFilePrivateMethod() {}  // явно файлоприватний член класу
    private func somePrivateMethod() {}          // явно приватний член класу
}

class SomeInternalClass {                        // неявно внутрішній клас
    var someInternalProperty = 0                 // неявно внутрішній член класу
    fileprivate func someFilePrivateMethod() {}  // явно файлоприватний член класу
    private func somePrivateMethod() {}          // явно приватний член класу
}

fileprivate class SomeFilePrivateClass {         // явно файлоприватний клас
    func someFilePrivateMethod() {}              // неявно файлоприватний член класу
    private func somePrivateMethod() {}          // явно приватний член класу
}

private class SomePrivateClass {                 // явно приватний клас
    func somePrivateMethod() {}                  // неявно приватний член класу
}

Кортежі

Рівнем доступу до типу-кортежу є найбільш обмежуючий рівень доступу з усіх типів, що використовуються в кортежі. Наприклад, якщо створити кортеж із двох різних типів, в одного з яких внутрішній рівень доступу, а у другого – приватний, рівень доступу кортежу буде приватним.

Примітка

Типи-кортежі не мають окремого визначення у спосіб, яким визначаються класи, структури, перечислення та функції. Рівень доступу до типу-кожтежу виводиться автоматично при використанні кортежу, і не може бути вказаним явно.

Функції

Рівень доступу до функції обчислюється по найбільш обмежуючому рівню доступу серед типів параметрів функції та типу, що повертається. Якщо обчислений рівень доступу до функції не відповідає контексту, його слід вказати явно у визначенні функції.

У прикладі нижче визначено глобальну функцію на ім’я someFunction(), без вказаного конкретного модифікатора рівня доступу до цієї функції. Можливо, ви будете очікувати, що рівнем доступу до цієї функції буде внутрішній, однак, це не той випадок. Насправді функція someFunction() у вигляді, як вона записана нижче, не скомпілюється:

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // тут йде реалізація функції
}

Типом, що повертається функцією, є кортеж, що складається із двох власних класів, що оголошені вище у підрозділі Власні типи. Один із класів є внутрішнім, а другий – приватним. Таким чином, загальний рівень доступу до всього кортежу є приватним (мінімальний рівень доступу серед типів-компонентів кортежу).

Оскільки тип, що повертається функцією, є приватним, слід позначити рівень доступу до функції теж приватним за допомогою відповідного модифікатора, і таким чином виправити оголошення функції:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // тут йде реалізація функції
}

Позначати оголошення функції someFunction() модифікаторами public чи internal, або використовувати внутрішній рівень доступу за замовчанням є некоректним, оскільки публічні чи внутрішні користувачі даної функції не матимуть доступу до приватного класу, що використовується у типі, котрий повертається даною функцією.

Перечислення

Окремі елементи перечислення автоматично отримують той же рівень доступу, що й перечислення, до якого вони належать. Не можна вказувати якийсь інший рівень доступу для окремих елементів перечислення.

У прикладі нижче, перечислення CompassPoint має явний явно вказаний публічний рівень доступу. Елементи перечислення north, south, east, та west таким чином мають публічний рівень доступу:

public enum CompassPoint {
    case north
    case south
    case east
    case west
}

Сирі значення та асоційовані типи

Типи сирих значення чи асоційованих значень в оголошенні перечислення повинні мати не менший рівень доступу, ніж рівень доступу перечислення. Наприклад, не можна мати сирі значення приватного типу у перечисленні із внутрішнім рівнем доступу.

Вкладені типи

Вкладені типи, що визначені всередині приватного типу, автоматично отримують приватний рівень доступу. Вкладені типи, що визначені у файлоприватному типі, автоматично отримують файлоприватний рівень доступу. Вкладені типи, що визначені у публічному чи внутрішньому типі автоматично отримують внутрішній рівень доступу. Якщо вкладений всередині публічного типу тип повинен бути публічно доступним, слід явно оголосити вкладений тип публічним.

Наслідування

Можна успадкувати будь-який клас, що є доступним у поточному контексті доступу. Клас-нащадок не може мати вищого рівня доступу, ніж має його батьківський клас: наприклад, не можна створити публічний нащадок внутрішнього класу.

Окрім того, можна заміщувати будь-який член класу (метод, властивість, ініціалізатор чи індекс), що є видимими у поточному контексті доступу.

Заміщення може зробити успадкований член класу доступнішим за його версію у батьківському класі. У прикладі нижче, клас A є публічним класом із файлоприватним методом на ім’я someMethod(). Клас B є нащадком класу A із рівнем доступу, зменшеним до внутрішнього. Тим не менш, клас B має заміщення методу someMethod() із рівнем доступу “внутрішній”, що є вищим за рівень доступу до оригінальної реалізації someMethod():

public class A {
    fileprivate func someMethod() {}
}

internal class B: A {
    override internal func someMethod() {}
}

У членах класу-нащадку коректним є навіть звернення до члена батьківського класу, що має нижчий рівень доступу за член класу-нащадку, за умови, що звернення до члена батьківського класу відбувається у місці, де це дозволено згідно з контекстом рівня доступу (тобто, всередині того ж вихідного файлу, де оголошено батьківський клас у випадку звернення до файлоприватного члену, або всередині того ж модуля, де оголошено батьківський клас у випадку звернення до внутрішнього члена):

public class A {
    fileprivate func someMethod() {}
}

internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}

Оскільки батьківський клас A та клас-нащадок B оголошені всередині одного вихідного файлу, для реалізації методу someMethod() у класі B виклик методу super.someMethod() є коректним.

Константи, змінні, властивості та індекси

Константи, змінні та властивості не можуть бути доступнішими за тип, в якому вони оголошені. Наприклад, приватний тип не може мати публічних властивостей. Аналогічно, індекс не може бути публічнішим за тип, до якого він належить, чи тип, що ним повертається.

Якщо константа, змінна, властивість чи індекс використовують приватний тип, ці константа, змінна, властивість чи індекс повинні бути також поміченими як приватні:

private var privateInstance = SomePrivateClass()

Гетери та сетери

Гетери та сетери для констант, змінних, властивостей та індексів автоматично отримують той же рівень доступу, що й константа, змінна, властивість чи індекс, до яких вони належать.

Сетеру можна дати нижчий рівень доступу, ніж має відповідний гетер, щоб обмежити доступ на читання-запис для змінної, властивості чи індексу. Для того, щоб застосувати нижчий рівень доступу, слід записати один з модифікаторів fileprivate(set), private(set), чи internal(set) перед ключовим словом var чи subscript.

Примітка

Дане правило працює як для властивостей, що зберігаються, так і для властивостей, що обчислюються. Хоч для властивостей, що зберігаються, геттери та сеттери не записуються явно, Swift тим не менше синтезує неявні геттери та сеттери для доступу до сховища за лаштунками для цих властивостей. Використання модифікаторів fileprivate(set), private(set), та internal(set) для зміни рівня доступу до синтезованого сеттера працює так само, як і для явного сеттера властивості, що обчислюється.

У прикладі нижче створено структуру на ім’я TrackedString, котра відслідковує кількість змін рядкової властивості:

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}

У структурі TrackedString оголошується рядкова властивість, що зберігається, на ім’я value, з початковим значенням "" (порожній рядок). Структура також визначає цілочисельну властивість, що зберігається, на ім’я numberOfEdits, котра використовується для відслідковування кількості змін властивості value. Відслідковування змін реалізовано за допомогою спостерігача за властивістю didSet властивості value, у котрому значення numberOfEdits збільшується на одиницю щоразу при присвоєнні властивості value нового значення.

Структура TrackedString та її властивість value не мають явних модифікаторів рівня доступу, тому вони обидві мають внутрішній рівень доступу за замовчанням. Однак, рівень доступу до властивості numberOfEdits встановлюється за допомогою модифікатора private(set), що вказує на те, що гетер властивості все ще має внутрішній рівень доступу, однак цю властивість можна змінити лише із коду всередині структури TrackedString. Це дозволяє структурі TrackedString змінювати значення numberOfEdits всередині себе, однак представляти цю властивість як властивість лише для читання для всього коду зовні даної структури.

Якщо створити екземпляр TrackedString та змінити його властивість value кілька разів, можна бачити зміну значення numberOfEdits, що співпадає із кількістю модифікації рядка value:

var stringToEdit = TrackedString()
stringToEdit.value = "Цей рядок буде відстежений."
stringToEdit.value += " Дане редагування збільшить numberOfEdits."
stringToEdit.value += " Так само як і це."
print("Кількість редагувань дорівнює \(stringToEdit.numberOfEdits)")
// Надрукує "Кількість редагувань дорівнює 3"

Хоча в іншому вихідному файлі й можна звертатись до поточного значення властивості numberOfEdits, його не можна змінити з іншого файлу. Це обмеження захищає деталі реалізації функціональності відслідковування змін всередині TrackedString, при цьому надаючи зручний доступ до аспекту даної функціональності.

Слід зазначити, що можна присвоїти явний рівень доступу як до гетера, так і до сетера, якщо це потрібно. У прикладі нижче показана явно публічна версія структури TrackedString. Члени структури (включно із властивістю numberOfEdits) таким чином мають внутрішній рівень доступу за замовчанням у публічній структурі. Їх можна зробити також публічними, при цьому гетер властивості numberOfEdits можна зробити публічним, залишивши сетер приватним, скомбінувавши модифікатори доступу public та private(set):

public struct TrackedString {
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
    public init() {}
}

Ініціалізатори

Власні ініціалізатори можуть мати рівень доступу, не більший за рівень доступу до типу, котрий вони ініціалізують. Єдиним виключенням є обов’язкові ініціалізатори (котрі описані у підрозділі [Обов’язкові ініціалізатори](/1_language_guide/13_initialization.md#Обов’язкові-ініціалізатори)). Обов’язкові ініціалізатори повинні мати той же рівень доступу, що й клас, до якого вони належать.

Як і з параметрами функцій та методів, типи параметрів ініціалізатора не можуть бути більш приватними, аніж рівень доступу до самого ініціалізатора.

Ініціалізатори за замовчанням

Як описано у підрозділі Ініціалізатори за замовчанням, Swift автоматично створює ініціалізатори за замовчанням без жодних аргументів для будь-якої структури чи базового класу, що має значення за замовчанням для всіх властивостей та не має хоча б одного явного ініціалізатора.

Ініціалізатор за замовчанням має такий же рівень доступу, як і тип, котрий він ініціалізує, крім випадків, коли цей тип є публічним. Для публічних типів ініціалізатор за замовчанням є внутрішнім.

Якщо потрібно мати публічний тип з ініціалізатором без аргументів, котрий можна використовувати в іншому модулі, потрібно явно створити публічний ініціалізатор без аргументів у визначенні даного типу.

Почленні ініціалізатори за замовчанням для структур

Почленний ініціалізатор за замовчанням для структур вважається приватним, якщо хоча б одна із властивостей структури, що зберігаються, є приватною. Аналогічно, якщо будь-яка із властивостей, що зберігаються, є файлоприватною, ініціалізатор буде файлоприватним. В інших випадках ініціалізатор матиме внутрішній рівень доступу.

Як і з ініціалізаторами за замовчанням, якщо публічна структура повинна мати доступний в інших модулях почленний ініціалізатор, його потрібно створити публічним явно у визначенні даної структури.

Протоколи

Якщо потрібно присвоїти явний рівень доступу до протоколу, слід це робити в момент визначення протоколу. Це дозволяє створювати протоколи, котрим можна підпорядковуватись лише у певному контексті доступу.

Рівень доступу кожної вимоги у визначенні протоколу автоматично співпадає із рівнем доступу самого протоколу. Вимозі протоколу не можна задати інший рівень доступу, аніж його має сам протокол. Це гарантує, що усі вимоги протоколу будуть видимі для будь-якого підпорядкованого протоколу типу.

Примітка

При створенні публічних протоколів, вимоги протоколу вимагатимуть публічного рівня доступу до реалізації цих вимог. Ця поведінка відрізняється від інших типів, де визначення типу публічним автоматично передбачає внутрішній рівень доступу до членів цього типу.

Наслідування протоколів

При визначенні нового протоколу, що наслідується від існуючого протоколу, новий протокол повинен мати не вищий рівень доступу, аніж протокол, від якого він наслідується. Не можна створити публічний протокол, що наслідується від внутрішнього протоколу.

Підпорядкування протоколу

Тип може підпорядковуватись до протоколу із нижчим рівнем доступу, аніж має він сам. Наприклад, можна створити публічний тип, що може використовуватись в інших модулях, але підпорядкування до внутрішнього протоколу може бути використаним лише всередині модуля, де оголошено внутрішній протокол.

Контекст, у якому тип підпорядковується до певного протоколу, визначається мінімальним з рівнів доступу до типу та до протоколу. Якщо тип є публічним, і підпорядкованим до внутрішнього протоколу, підпорядкування до цього протоколу є також внутрішнім.

При створенні типу чи розширенні його для підпорядкування протоколу, слід гарантувати, що реалізація кожної вимоги протоколу у типі має як мінімум такий же рівень доступу, як і рівень доступу підпорядкування до протоколу. Наприклад, якщо публічний тип є підпорядкованим до внутрішнього протоколу, реалізація кожної вимоги протоколу повинна бути хоча б внутрішньою.

Примітка

У Swift, так само як і в Objective-C, підпорядкування до протоколу є глобальним: неможливо підпорядкувати тип до протоколу у два різних способи в одній програмі.

Розширення

Клас, структуру чи перечислення можна розширити у будь-якому контексті доступу, в якому ці клас, структура чи перечислення є доступними. Будь-який член типу, що додається у розширенні, має той же рівень доступу за замовчанням, що й члени типу, оголошені в оригінальному типі, котрий розширюється. Якщо розширити публічний чи внутрішній тип, будь-які нові члени, що додаються, матимуть внутрішній рівень доступу за замовчанням. Якщо розширити файлоприватний тип, будь-які нові члени, що додаються, матимуть файлоприватний рівень доступу за замовчанням. Якщо розширити приватний тип, будь-які нові члени, що додаються, матимуть приватний рівень доступу за замовчанням.

Також можна помітити розширення модифікатором рівня доступу явно (наприклад, private extension) для задання нового рівня доступу за замовчанням для всіх визначених у даному розширенні членів. Цей новий рівень доступу за замовчанням все ще можна замістити всередині розширення для окремих членів типу.

Не можна вказувати явно модифікатор рівня доступу для розширення, що використовується для підпорядкування типу до протоколу. Для визначення рівня доступу за замовчанням для реалізації кожної з вимог протоколу використовується рівень доступу до самого протоколу.

Приватні члени у розширеннях

Розширення, що містяться в тому ж файлі, що й клас, структура та перечислення, яке вони розширюють, поводяться так, ніби код у цих розширеннях було написано як частина оригінального оголошення типу. Як результат, можна:

  • Оголошувати приватні члени в оригінальному оголошенні, і звертатись до цих членів у розширенні в тому ж файлі.
  • Оголошувати приватні члени в одному розширенні, та звертатись до цих членів у іншому розширенні у цьому ж файлі.
  • Оголошувати приватні члени у розширенні, та звертатись до цих членів у оригінальному оголошенні в тому ж файлі.

Ця поведінка дозволяє використовувати розширення для організації та групування вашого коду, незалежно від того, чи є у ваших типах приватні сутності. Наприклад, нехай є простий протокол:

protocol SomeProtocol {
    func doSomething()
}

Можна використати розширення для підпорядкування протоколу, як це:

struct SomeStruct {
    private var privateVariable = 12
}

extension SomeStruct: SomeProtocol {
    func doSomething() {
        print(privateVariable)
    }
}

Узагальнення

Рівень доступу до узагальненого типу чи функції є мінімальним із рівнів доступу до самого узагальненого типу чи функції та рівнів доступу до кожного з обмежень на параметри типу.

Псевдоніми типів

Будь-який визначений вами псевдонім типу розглядається як окремий тип з метою контролю доступу. Псевдонім типу може мати рівень доступу не більший за рівень доступу до самого типу. Наприклад, приватний псевдонім типу може бути псевдонімом до приватного, файлоприватного, внутрішнього, публічного чи відкритого типу, але публічний псевдонім типу не може бути псевдонімом до внутрішнього, файлоприватного чи приватного типу.

Примітка

Дане правило також застосовується до псевдонімів для асоційованих типів, що використовуються для задоволення підпорядкувань до протоколів.