ProgrammingiOS Architect/Library Developer

How does access control work for nested types and members in Swift? What accessibility issues may arise when composing modules and libraries?

Pass interviews with Hintsage AI assistant

Answer.

In Swift, access levels (private, fileprivate, internal, public, open) apply not only to classes, structures, and their properties but also to nested types. A nested type by default inherits the access level of its enclosing type unless a different explicit restriction is specified.

Key nuances:

  • If the enclosing type is declared as internal, the nested type cannot have a more open access level than the outer type but can be more 'closed' (for example, outer — public, nested — private).
  • When compiling across different modules (frameworks), nested types declared as internal will not be visible from other modules.

Example:

public class A { public struct B { fileprivate func foo() {} } }

In this example, both A and B are public, but the method foo() is file-private.

Trick question.

Question: "Can a nested type have a higher access level than its enclosing type?"

Answer: No, the access level of a nested type cannot exceed the access level of its enclosing type. If you attempt to declare a nested type with a higher access level, the compiler will produce an error.

Example of an error:

internal struct MyStruct { public enum MyEnum { ... } // Error: public cannot be inside internal }

Examples of real errors due to ignorance of the nuances of the topic.


Story 1

In a general framework, the access levels of nested structures were not synchronized with external types. In the release version, this led to the inability to use internal enums in the client application, requiring an urgent interface change.


Story 2

In a large project, an internal service object had a nested class with statuses declared as internal. After the addition of a new module that depended on this class, integration became impossible without raising the access level and fully recompiling the SDK.


Story 3

In a complex library, some nested structures were declared as public, while the container itself was internal. During the migration to a new version, critical errors arose: public types did not compile in an external context, which delayed updates across multiple teams.