ProgrammingiOS Developer

Explain the principles of access to private/protected/internal/public/open in Swift. When is it better to use each of the modifiers, and what errors can you encounter in a real project?

Pass interviews with Hintsage AI assistant

Answer

In Swift, there are five levels of access to type members (properties, methods, etc.) and types themselves:

  • open — the highest degree of public visibility. Can be inherited and overridden even outside the module.
  • public — accessible outside the module, but cannot be overridden/inherited.
  • internal (default) — accessible within the module.
  • fileprivate — accessible only within the file.
  • private — accessible only within the declaration scope (extension is also in this scope).

Usage rules:

  • Use private for logic that should not be visible outside the declaration.
  • fileprivate — if data needs to be shared within the same file (for example, between two related extensions).
  • internal — default for everything public within the module.
  • public/open — for APIs used by other modules/frameworks.

Example:

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

Trick question

How does open differ from public when describing a class? Why are not all public classes available for inheritance?

Answer: open marks the class/method as available for overriding and inheritance outside its module. public only opens access for use but does not allow creating subclasses outside the module. On one hand, this protects the implementation from unwanted changes, on the other — opens only the necessary extension points.

public class PublicClass {} open class OpenClass {} // In another module: class InheritFromOpen: OpenClass {} // OK class InheritFromPublic: PublicClass {} // Error!

Examples of real errors due to lack of knowledge about the nuances of the topic


Story

In a common library, a class was marked as public, and an external project tried to extend it by overriding methods. The project did not compile due to a misunderstanding of the difference between public and open — it cost the team an extra week of interface refinement.


Story

Within a single file, there was an attempt to access a private property from an extension — but the property was declared not as fileprivate, but as private. This led to a compiler error that was only noticed during the integration build.


Story

In an application with multiple frameworks, all types were marked as internal (by default). When it became necessary to use types between modules, the interface was not accessible — it was necessary to rewrite dozens of declarations to public, which took additional time and testing.