The special // MARK: Some text
comment should be used to group related methods into sections (#pragma mark
in objc).
This menu can be revealed either by tapping the name of the current method in the “jump bar” at the top of your source editor or by pressing ^6
(you can rebind this to something more convenient). One great feature of this method list is that you can type to fuzzy filter the list and press [Return]
to jump to the selected method.
You may also use // MARK: - Some text
to insert a dividing line (such as you can see for “Notifications” and “UIScrollViewDelegate”)
Xcode is flexible with whitespace here, but our rules are:
//
and MARK
MARK
and :
:
Please attempt to follow these recommendations when marking groups of methods:
// MARK: Some label
(no hyphen). If the section is outside a type declaration, use // MARK: - Some label
(with a hypen).UIViewController
, attempt to use these standardized section names:
init()
and deinit()
, if any)// MARK: - UITableViewDelegate
// MARK: - Table view delegate
becomeFirstResponder
should belong to a UIResponder
mark sectionsizeThatFits:
should probably belong to a Layout
section rather than UIView
since the functionality trumps where it was inherited fromHaving a consistent mechanism for grouping allows everyone on the team to nagivate the codebase with much greater ease and efficiency. Knowing how files for commong view controllers, for example, are laid out makes working on them much faster and simpler.
// bad: does not use the name of the protocol as the name of the section
// MARK: - Table view delegate
...
// good: use the name of the protocol directly as the name of the section
// MARK: - UITableViewDelegate
...
// bad: using the same section for UITableViewDelegate and UITableViewDataSource protocols
// MARK: - UITableViewDelegate and UITableViewDataSource
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
...
}
public func numberOfSections(in tableView: UITableView) -> Int {
...
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
...
}
// good: using different sections for UITableViewDelegate and UITableViewDataSource protocols
// MARK: UITableViewDelegate
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
...
}
// MARK: UITableViewDataSource
public func numberOfSections(in tableView: UITableView) -> Int {
...
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
...
}
Most “important” stuff at the top; and least “important” stuff at the bottom. The importance is usually determined by the access level; the less restrictive the access level, the more “important” it is.
Ordering file contents by access level ensures that the entities with the least restrictive access level get the most visibility, which are likely the components that developers interact with the most.
// public enums, classes, interfaces etc.
public class House {
// public functions
public init {
// ...
}
// public variables
public static let continent = "Westeros"
// internal functions
internal func addHouseMember() {
// ...
}
// internal variables
internal let sigil: Animal
// fileprivate functions
fileprivate func updateHouseAllegiance() {
// ...
}
// fileprivate variables
fileprivate var hasAllies: Bool
// private functions
private func reorganizeHouse() {
// ...
}
// private variables
private var size: Int = 0
}
// internal functions
internal func updateUnalliedHouses(_ houses: [House]) {
houses.forEach { house in
// since this top-level function is in the same file, it can access fileprivate funcs and vars
if !house.hasAllies {
house.updateHouseAllegiance()
}
}
}
// private extensions or constants
private maximumHouseSize: Int = 50
Use structs or nested structs to group constants when possible; the grouping should be based on logical use instead of structure or type of the constants.
This reduces verbosity and provides structure.
class FruitSellerView: UIView {
...
// bad: no separation between rotation and fade animation constants, long constant names are harder to read
private enum Constants {
static let rotationAnimationAngle: CGFloat = .pi / 45.0
static let rotationAnimationDelay: CGFloat = 0.15
static let rotationAnimationDuration: CGFloat = 0.3
static let rotationAnimationSpeed: CGFloat = 100
static let fadeAnimationDelay: CGFloat = 0.1
static let fadeAnimationDuration: CGFloat = 0.25
static let fadeAnimationSpeed: CGFloat = 200
}
// bad: the name "Strings" does not provide helpful about how the constants are used.
private enum Strings {
static let rotationAnimationIdentifier: String = "FruitSellerViewRotationAnimationIdentifier"
static let fadeAnimationIdentifier: String = "FruitSellerViewFadeAnimationIdentifier"
}
}
class FruitSellerView: UIView {
...
// good: split rotation and fade animation constants into different groups
private enum RotationAnimationConstants {
static let angle: CGFloat = .pi / 45.0
static let delay: CGFloat = 0.15
static let duration: CGFloat = 0.3
static let speed: CGFloat = 100
static let identifier: String = "FruitSellerViewRotationAnimationIdentifier"
}
private enum FadeAnimationConstants {
static let delay: CGFloat = 0.1
static let duration: CGFloat = 0.25
static let speed: CGFloat = 200
static let identifier: String = "FruitSellerViewFadeAnimationIdentifier"
}
}
Note: We use enum
rather than struct
as it can help reduce potential confusion. Running let x = RotatationAnimationConstants()
would be valid code if we were to use a struct
, for an enum
it will throw an error.