Уровни доступа в Swift

Корректное использование уровней доступов в Swift способно скрыть детали реализации вашего кода от посторонних глаз от кода в других файлах и модулях. Очень часто именно с этой темы начинается собеседование iOS разработчика.

В нашем распоряжении пять уровней доступа: 

  • Open;
  • Public; 
  • Internal;
  • Private;
  • File-private.

К сожалению, не помню ресурс-источник следующей картинки, но по ней очень легко понять тему контроля доступа:

Уровни доступа в Swift - вопрос на собеседовании

Open — это наивысший уровень доступа. Он позволяет получить доступ к объекту как в целевом модуле, так и за его пределами. Вы можете создать подкласс или переопределить open-объект в любом модуле.

Public — то же самое, что и Open. Отличие в том, что Public доступ позволяет переопределять и создавать подкласс объекта только внутри целевого модуля (Target). Другими словами, доступ к объекту из других модулей остается.

Internal — этот уровень доступа используется по умолчанию в Swift. На уровне Internal доступ к объекту есть только внутри текущего модуля. Соответственно, создание подклассов и переопределение доступно тоже только в текущем модуле.

File-private — на этом уровне у вас есть доступ к элементам данных и функциям в рамках текущего файла. Обычно используется, когда в текущем исходном файле необходимо скрыть реализацию.

Private — это самый низкий уровень доступа. Если декларация или расширение текущего файла включает сущность, то Private set ограничивает ее использование. У вас нет контроля доступа в подклассах или в других файлах.

Синтаксис уровней доступа

Чтобы установить уровень доступа, необходимо поместить его перед объявлением объекта: 

public class PublicClass {}
internal class InternalClass {}
fileprivate class FilePrivateClass {}
private class PrivateClass {}

Как говорилось ранее, если не указать уровень доступа, то по умолчанию будет стоять дефолтный уровень internal.

Разница между уровнями доступа Open и Public (вопрос на собеседовании)

Обычно на собеседовании спрашивают разницу либо между Open и Public, либо между Private и Fileprivate доступами.

На самом деле уровни доступа Open и Public сильно отличаются друг от друга. Уровень доступа Open необходим для ограничения на наследование классов в Swift. Это означает, что уровень Open можно применить только к классам и членам класса (свойства и методы).

Open класс может быть подклассом в модуле, в котором он определен. Также он может быть подклассом в модулях, которые импортируют модуль с нашим классом. То же самое относится и к open членам класса.

Public классы могут быть подклассами только в модуле, в котором они определены. То же самое относится к public членам класса.

Пример с уровнем доступа Open

Если на собеседовании вас попросят привести пример реализации с уровнем доступа Open, то вы смело можете рассказать про Core Data.

@available(iOS 3.0, *)
open class NSManagedObject : NSObject {    

    @available(iOS 3.0, *)
    open class var contextShouldIgnoreUnmodeledPropertyChanges: Bool { get }

    @available(iOS 10.0, *)
    open class func entity() -> NSEntityDescription
...

Если бы Apple использовали тип доступа public к методам класса NSManagedObject, то разработчики не смогли бы переопределять все эти методы в своих NSManagedObject подклассах. Именно для этого и предназначено разделение на public и open уровни доступа.

Разница между уровнями доступа Private и Fileprivate (вопрос на собеседовании)

С этим вопросом немного проще. Private дает доступ к членам данных и функциям в рамках их объявления или расширения в текущем файле. Fileprivate дает доступ к членам данных и функциям в одном и том же исходном файле или в подклассе/расширении.

// Объявляем класс А с двумя переменными
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?

    func accessMySelf() {
        // Доступ к переменным будет работать корректно
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}

// Объявляем класс B (в том же файле) для доступа к классу А
class B {
    func accessA() {
        // Создаем экземпляр класса A 
        let aObject = A()

        // Ошибка — нет доступа
        aObject.aPrivate = "Error"

        // Доступ есть
        aObject.aFileprivate = "Access"
    }
}

Дополнительный материал:

Выразить благодарность или найти уникальный материал вы можете в boosty.

Подписывайтесь на мой Telegram-канал iOS Interview Channel, чтобы не пропустить новый материал.


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *