Привет!
Это видео посвящено разграничению доступа к методам,
переменным и инициализаторам типов.
Контроль доступа помогает скрыть детали реализации вашего типа
и определить правильный интерфейс.
Уровень доступа может быть определен как для типа,
так и для отдельных его составляющих.
Для начала разберемся с теорией.
В Swift разрешено изменять доступ к модулям и исходным файлам.
Под модулем подразумевается код, входящий в состав фреймворка или приложения,
который распространяется, как единое целое,
и может быть добавлен в проект в качестве ключевого слова Import.
Каждая цель для сборки приложения считается отдельным модулем.
Все, что вы определите в фреймворке для инкапсулирования логики приложения с целью
дальнейшего переиспользования, будет доступно в качестве отдельного модуля.
Этот модуль смогут использовать как приложения, так и другие фреймворки.
Файл с исходным кодом является частью модуля и содержит описание одного или
нескольких типов внутри себя.
В Swift определены 5 уровней доступа.
Open и Public доступы позволяют обращаться к сущностям из любого модуля.
Используйте эти модификаторы для описания общих интерфейсов.
Public позволяет использовать наследование и переопределение только внутри модуля,
в котором они объявлены.
Open же может использоваться только классами и членами классов,
но позволяет наследоваться и выполнять переопределение любому модулю,
который импортировал наш код.
Internal дает возможность работать с сущностями в рамках существующего модуля.
File-private ограничивает доступ рамками текущего файла.
Используется для сокрытия деталей реализации участка кода,
когда реализация осуществляется в рамках одного файла.
Private же позволяет работать с сущностями внутри определяющего их блока.
Или в расширении, но только в текущем файле.
Уровни доступа описаны от самого доступного, до самого ограниченного.
Важно запомнить то, что сущность с более высоким уровнем доступа не
может быть определена внутри сущности с более низким уровнем доступа.
По умолчанию, всем сущностям назначается уровень доступа Internal.
Поэтому в большинстве ситуаций определять его явно нет необходимости.
При создании приложения с единственной целью — для сборки — Internal
удовлетворяет всем необходимым потребностям.
И нет необходимости в явном видеоуказании прав на сущности.
Однако вы можете пометить части кода ключевыми словами Private и File-private
для скрытия деталей реализации внутри модуля.
Разработка фреймворков подразумевает создание интерфейса для общего доступа.
Поэтому логично отмечать публичные сущности ключевыми словами Open и Public.
Что же касается внутренней реализации фреймворка, уровень доступа к ней можно не
задавать, а использовать принятый по умолчанию Internal.
При написании юнит-тестов, им необходим доступ к тестируемому модулю.
Для этого сущности модуля должны быть отмечены как Public или Open.
Однако вы можете использовать атрибут Testable при импорте модуля.
Тогда внутренняя реализация сущности будет также доступна для юнит-тестов.
Однако сущности, помеченные как Private и File-private все еще не будут доступны.
Уровень доступа задается при помощи ключевого слова перед указанием типа
сущности.
По умолчанию, как мы уже говорили ранее,
уровень доступа устанавливается как Internal.
Если вы хотите задать уровень доступа для собственного типа,
делайте это на этапе его описания.
Уровень доступа, указанный для типа, будет установлен для всех сущностей,
содержащихся в нем.
Исключением является Public.
Если вы задали модификатор доступа Public для типа, то автоматически для сущностей,
содержащихся в нем, будет задан доступ Internal.
Устанавливать уровень доступа Public необходимо вручную для каждой сущности.
А теперь поговорим о кортежах.
Уровень доступа для них не указывается явно.
Он всегда автоматически определяется из членов, входящих в него.
Уровень доступа устанавливается минимально возможный.
Например, если в кортеж входят типы с доступом Public и Private,
то для кортежа будет установлен доступ Private.
Аналогично и для функций.
Уровень доступа автоматически устанавливается на основе параметров
и возвращаемого типа.
Уровень доступа должен быть указан явно, если он не соответствует общему контексту.
В данном случае функция возвращает кортеж с параметрами доступа Public и Private.
Для функции явно необходимо указать уровень доступа Private.
В перечислениях входящие в него кейсы получают тот же модификатор доступа,
что и сам enumeration, к которому они принадлежат.
Если используются raw или ассоциированные значения, то их уровень доступа должен
быть не меньше, чем у перечисления, их содержащего.
Вы можете наследоваться от любого класса, доступного в данном контексте.
При этом уровень доступа для наследника не может быть выше, чем у супер-класса.
Однако для методов и переменных, которые вы переопределяете,
уровень доступа может быть изменен на желаемый.
Как вы видите в примере, наследуемому классу разрешается получить доступ к
File-private полям базового класса,
если доступ осуществляется в рамках необходимого контекста.
В данном случае оба класса объявлены в одном файле,
и уровень доступа File-private позволяет обращаться к методу.
Константы, переменные,
поля и сабскрипты не могут иметь уровень доступа выше, чем их тип.
Если для типа определен доступ Private,
то и для инстанса должен быть определен тот же модификатор.
Сеттеры и геттеры получают тот же уровень доступа, что и свойства.
Но вы можете, например, переопределить уровень доступа для сеттера.
Для того, чтобы сделать свойства доступными только для чтения.
В нашем примере создается структура со свойствами, доступными только для чтения.
Вы можете прочитать значения данной переменной при обращении к инстансу, но
изменить значения для Access-counter можно только из контекста структуры Logger.
Геттеру также можно установить приватный уровень доступа,
но выполняется это немного иначе.
Инициализатором может быть назначен уровень доступа меньший или равный
доступу, определенному для типа.
Исключением является Required инициализатор.
Ему должен соответствовать тот же доступ, что и типу.
То же правило касается и инициализаторов по умолчанию.
У структур инициализатор будет иметь уровень доступа,
соответствующий минимальному доступному для всех свойств, входящих в структуру.
Если одно из свойств объявлено как Private,
то и инициализатор структуры будет иметь доступ Private.
Для протоколов модификатор доступа указывается при их объявлении.
Требования в протоколе не могут быть объявлены с более низким уровнем,
чем сам протокол.
Это позволяет добиться того, что при поддержке протокола все требования
будут доступны для типа, который его поддерживает.
В отличие от других типов, при указании доступа Public,
он будет распространен на все требования внутри протокола.
Определение нового протокола на основе существующего не позволит установить более
высокий доступ, чем у базового протокола.
Вы не сможете определить Public-протокол, если он наследуется от Private-протокола.
Расширения для классов структур и перечислений имеют тот же уровень доступа,
что и тип, для которого они создаются.
Если для типа указан доступ Private, то и сущности,
объявленные в расширении, имеют модификатор Private.
Для расширения можно явно указать уровень доступа, если такая необходимость имеется.
Но он не может быть выше, чем у расширяемого типа.
Например, выполнение подобного кода приведет к ошибке компиляции.
Если расширение для типа описано в том же файле, что и сам тип,
то оно может получить доступ к сущностям, объявленным с модификатором Private.
В качестве примера показана структура и extension для нее,
внутри которого удается получить доступ к приватной переменной.
В данной лекции мы рассмотрели возможности для ограничения доступа к участкам кода.
А также увидели, как они реализованы для разных типов и сущностей.