While we use SwiftLint in the SDK to adhere to a general style, there are some guidelines that are not able to be captured by our linter rules. Those guidelines are defined in this document.
These rules are in addition to, and should not contradict, the official Swift API Design Guidelines.
Write a documentation comment for all declarations (ex: functions, methods, variables, constants, enumerations, structs, classes, and protocols).
Format documentation comments using Swift's dialect of Markdown. Prefer styling generated by Xcode's CMD+OPT+/
.
Use // MARK: -
to separate the contents of type definitions and extensions into the sections below, in order:
// MARK: - Public Properties
forpublic
andopen
properties.// MARK: - Internal Properties
forinternal
,fileprivate
, andprivate
properties.// MARK: - Public Methods
forpublic
andopen
methods.// MARK: - Internal Methods
forinternal
,fileprivate
, andprivate
methods.// MARK: - <PROTOCOL>
for protocol conformance. Each protocol conformance gets a separateMARK
.// MARK: - <EXTENSION>
for additional extensions.
Use a newline before and after a MARK
.
When conforming to a protocol, add a separate extension for the protocol methods.
Preferred:
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
Not Preferred:
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
When defining struct model types that depend on other custom struct definitions, put both definitions in the same file.
Special cases can be made for massive structs (over 100 lines), which is unlikely to occur.
Preferred:
// Musician.swift //
struct Musician: Codable {
let name: String
let recordLabel: RecordLabel
}
struct RecordLabel: Codable {
let name: String
let address: Address
}
struct Address: Codable {
...
}
Not Preferred:
// Musician.swift file
struct Musician: Codable {
let name: String
let recordLabel: RecordLabel
}
// RecordLabel.swift file
struct RecordLabel: Codable {
let name: String
let address: Address
}
// Address.swift file
struct Address: Codable {
...
}
Method braces and other braces (if
/else
/switch
/while
etc.) always open on the same line as the statement but close on a new line.
Preferred:
if user.isHappy {
// Do something
} else {
// Do something else
}
Not Preferred:
if user.isHappy
{
// Do something
}
else {
// Do something else
}
Colons have no space on the left and one space on the right. Exceptions are the ternary operator ? :
, empty dictionary [:]
and #selector
syntax addTarget(_:action:)
.
Preferred:
class TestDatabase: Database {
var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}
Not Preferred:
class TestDatabase : Database {
var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}
There should be one blank line between methods and up to one blank line between type declarations to aid in visual clarity and organization. Whitespace within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods.
There should be no blank lines after an opening brace or before a closing brace. An exception is when defining a class/struct/etc per our linter rules.
Preferred:
if isTrue {
// do something
}
Not Preferred:
if isTrue {
// do something
}
Long function invocations should line break on each argument. Closing parentheses should appear on a line by themselves.
Preferred:
let user = try await getUser(
for: userID,
on: connection
)
Not Preferred:
let user = try await getUser(
for: userID,
on: connection)
Prefer the shortcut versions of type declarations over the full generics syntax.
Preferred:
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
Not Preferred:
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
Acronyms and initialisms that commonly appear as all upper case in American English should be uniformly up- or down-cased according to case conventions.
Preferred:
var orderID
var dataUTF8
var requestHTTP
Not Preferred:
var orderId
var dataUtf8
var requestHttp
When launching session data tasks, prefer to resume the session inline vs creating a property for the task. This ensures that it is clear where we are kicking off the session to make the request.
Preferred:
session.dataTask(with: request) { [weak self] data, response, error in
// Do request stuff
}.resume()
Not Preferred:
let task: URLSessionTask = session.dataTask(with: request) { [weak self] data, response, error in
// Do request stuff
}
task.resume()
We prefer to always rely on implicit returns to cleanup our codebase overall.
Preferred:
func sendAString() -> String {
"my-very-cool-string"
}
var aString: String {
"my-very-cool-string"
}
Not Preferred:
func sendAString() -> String {
return "my-very-cool-string"
}
var aString: String {
return "my-very-cool-string"
}
When not in an initalizer remove the use of self where possible. For initalizers we prefer the implicit self.
Preferred:
var myString: String
var myInt: Int
init(myString: String, myInt: Int) {
self.myString = myString
self. myInt = myInt
}
func sendMyStuff() -> [String] {
[myString]
}
Not Preferred:
var myString: String
var myInt: Int
init(myString: String, myInt: Int) {
myString = myString
myInt = myInt
}
func sendMyStuff() -> [String] {
[self.myString]
}