ПрограммированиеiOS разработчик

Объясните принцип работы доступа к private/protected/internal/public/open в Swift. Когда лучше использовать каждый из modifier-ов, и с какими ошибками можно столкнуться на реальном проекте?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Swift существует пять уровней доступа к членам типов (свойства, методы, т.д.) и самим типам:

  • open — максимальная степень публичности. Можно наследовать и переопределять даже за пределами модуля.
  • public — доступно вне модуля, но нельзя переопределять/наследовать.
  • internal (по умолчанию) — доступно внутри модуля.
  • fileprivate — доступно только в рамках файла.
  • private — доступно только в пределах области объявления (extension тоже в этом scope).

Правила использования:

  • Используйте private для логики, которая не должна быть видна нигде вне объявления.
  • fileprivate — если требуется обмен данными в одном файле (например, между двумя связанными extensions).
  • internal — дефолт для всего общедоступного в модуле.
  • public/open — для API, используемых другими модулями/фреймворками.

Пример:

open class MyOpenClass {} public class MyPublicClass {} internal class InternalClass {} fileprivate class FilePrivateClass {} private class PrivateClass {}

Вопрос с подвохом

Чем open отличается от public при описании класса? Почему не все public классы доступны для наследования?

Ответ: open помечает класс/метод доступным для переопределения и наследования за пределами своего модуля. public только открывает доступ к использованию, но не позволяет делать наследников вне модуля. С одной стороны, это защищает реализацию от нежелательных изменений, с другой — открывает только нужные точки расширения.

public class PublicClass {} open class OpenClass {} // В другом модуле: class InheritFromOpen: OpenClass {} // OK class InheritFromPublic: PublicClass {} // Ошибка!

Примеры реальных ошибок из-за незнания тонкостей темы


История

В общей библиотеке класс был отмечен как public, и внешний проект попытался расширить его, переопределив методы. Проект не компилировался из-за ошибочного понимания разницы public и open — это стоило команде лишней недели доработки интерфейса.


История

Внутри одного файла попытались получить доступ к private-свойству из extension — но свойство было объявлено не как fileprivate, а как private. Это привело к компиляторной ошибке, которую заметили только на интеграционной сборке.


История

В приложении с несколькими фреймворками все типы помечались как internal (по умолчанию). Когда понадобилось использовать типы между модулями, интерфейс был не доступен — пришлось переписывать десятки объявлений на public, что заняло дополнительное время и тестирование.