A file should only contain one major type declaration. Other types are allowed in support of the main type that is represented by the file, which typically shares the name of the file, e.g. LoginViewController.swift
would have a major type of LoginViewController
.
In the example below, we have declared multiple top level enums and classes within one file. The class declarations should be split across multiple files and the enums should be encapsulated within their respective classes when it makes sense.
/// An enum to track whether or not the user is logged in or not
enum AuthState {
case loggedIn
case loggedOut
}
/// An enum to track where the user is in the signup / onboarding process
enum SignupState {
case onboardingComplete
case signupComplete
}
/// A UIViewController subclass that encapsulates functionality for a Login Screen
class LoginViewController: UIViewController {
/// ...
}
///A UIViewController subclass that encapsulates functionality for a Signup Screen
class SignupViewController: UIViewController {
/// ...
}
In the example below, the file has only one major type declaration. The protocol and extension are supporting the major type of LoginViewController
and therefore allowed to be in this file.
protocol LoginViewControllerDelegate {
/// ...
}
/// A UIViewController subclass that encapsulates functionality for a Login Screen
class LoginViewController: UIViewController {
/// ...
}
extension LoginViewController {
// MARK: - LoginViewController
}
-
Files are organized in the following order:
- Default header created by Xcode
- Import statements
- Protocols that are associated primarily with the major type declaration of the file, each followed by a corresponding default protocol implementations, if applicable.
- The major type declaration of the file
- Nested type declarations
- Properties
- Inherited
- Protocol
IBOutlet
s- Open
- Public
- Internal
- Private
- Functions
- Inherited
- Protocol
- Open
- Public
- Internal
- Private
- Extension protocol conformances
- Private extensions of other types
-
Initializers, when implemented, should be the first declaration(s) in each group (inherited, protocol, open, etc.) of functions.
-
deinit
, when implemented, should come directly after the last initializer. If no initializers exist,deinit
should come before all other function declarations. -
For
Codable
conformance, it may be necessary to implement the special nested typeCodingKeys
, which conforms toCodingKey
. When present, this nested type should be declared after all other nested types. SinceCodingKeys
andCodingKey
are not documented as part of theCodable
protocols, noMARK
is necessary. -
Default protocol implementation extensions should never include additional methods or properties unless they are
private
to the extension and only used in the default implementation(s).
Group and separate code using MARK
. The grouping order for each section of properties and functions should be:
- Overridden declarations
- Declarations for protocol conformance
- Declarations being introduced in the major type of the file
- We only use
MARK
when a file has overrides or conformances. MARK
separates where things were originally declared.- Always use
MARK: -
for grouping based on type.- The text should be the type you are grouping by.
- Use
MARK:
for other groupings inside ofMARK: -
, e.g.MARK: Helper Functions
. - When adding a
MARK
for an extension, make sure it is inside the extension. - Default protocol implementation extensions do not require a
MARK
.
/// A view controller that displays an example.
class ExampleViewController: UIViewController {
// MARK: - UIViewController
override var extendedLayoutIncludesOpaqueBars: Bool {
set {
}
get {
return true
}
}
// MARK: - UITraitEnvironment
override var traitCollection: UITraitCollection {
return UITraitCollection(userInterfaceIdiom: .phone)
}
// MARK: - ExampleViewController
@IBOutlet private weak var exampleView: UIView!
private let urlSession: URLSession
// MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
// MARK: - NSCoding
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - UITraitEnvironment
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
view.backgroundColor = .red
}
// MARK: - ExampleViewController
/// Initializes the `ExampleViewController` with the required parameters.
///
/// - Parameter urlSession: The url session the controller should use.
init(urlSession: URLSession) {
self.urlSession = urlSession
super.init(nibName: nil, bundle: nil)
}
private func retrieveExample() {
// ...
}
}
extension ExampleViewController: UINavigationControllerDelegate {
// MARK: - UINavigationControllerDelegate
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// ...
}
}