The aim of this guide is to help developers in writing clean, concise, beautiful and easy to read Swift codes. The main goals:
- to make it hard to write programmer errors, or at least make them hard to miss
- to increase readability and clarity of intent
- to minimize unnecessary code bloat
- to have a nice look of code
Cause: This is Swift
- Preferred
self.backgroundColor = UIColor.whiteColor()
self.completion = {
// ...
}
- Not Preferred
self.backgroundColor = UIColor.whiteColor();
self.completion = {
// ...
};
It's preferred to use tab to indent the code instead of using spaces. Tab setting could be set at Xcode's Text Editing settings. As following:
Cause: This prevents no-trailing-newline errors and reduces noise in commit diffs.
- Preferred
class Button {
// ...
}
// <-- One line here
- Not Preferred
class Button {
// ...
} // <-- No new line after
class Button {
// ...
}
// <-- One line here
// <-- Another line here
Cause: Gives breathing room between code blocks.
- Preferred
class BaseViewController: UIViewController {
// ...
override viewDidLoad() {
// ...
}
override viewWillAppear(animated: Bool) {
// ...
}
}
Cause: Readability
- Preferred
func <| (lhs: Int, rhs: Int) -> Int {
// ...
}
let value = 1 <| 2
- Not Preferred
func <|(lhs: Int, rhs: Int) -> Int {
// ...
}
let value = 1<|2
Cause: Readability
- Preferred
func doSomething(value: Int) -> Int {
// ...
}
- Not Preferred
func doSomething(value: Int)->Int {
// ...
}
Commas (,
) should have no whitespace before it, and should have either one space or one newline after.
Cause: Keeps comma-separated items visually separate.
- Preferred
let array = [1, 2, 3]
self.presentViewController(
controller,
animated: true,
completion: nil
)
- Not Preferred
let array = [1,2,3]
let array = [1 ,2 ,3]
let array = [1 , 2 , 3]
self.presentViewController(
controller ,
animated: true,completion: nil
)
Colons (:
) used to indicate type should have one space after it and should have no whitespace before it.
Cause: The colon describes the object to its left, not the right.
- Preferred
func createItem(item: Item)
var item: Item? = nil
- Not Preferred
func createItem(item:Item)
func createItem(item :Item)
func createItem(item : Item)
var item:Item? = nil
var item :Item? = nil
var item : Item? = nil
Colons (:
) for case
statements should have no whitespace before it, and should have either one space or one newline after it.
Cause: Same as he previous rule, the colon describes the object to its left, not the right.
- Preferred
switch result {
case .Success:
self.completion()
case .Failure:
self.failure()
}
- Not Preferred
switch result {
case .Success :
self.completion()
case .Failure:self.reportError()
}
Cause: Separates the brace from the declaration.
- Preferred
class Icon {
// ...
}
let block = { () -> Void in
// ...
}
- Not Preferred
class Icon{
// ...
}
let block ={ () -> Void in
// ...
}
Open braces ({
) for type declarations, functions, and closures should be followed by one empty line. Single-statement closures can be written in one line.
Cause: Gives breathing room when scanning for code.
- Preferred
class Icon {
let image: UIImage
var completion: (() -> Void)
init(image: UIImage) {
self.image = image
self.completion = { [weak self] in self?.didComplete() }
}
func doSomething() {
self.doSomethingElse()
}
}
- Not Preferred
class Icon {
let image: UIImage
init(image: UIImage) {
self.image = image
self.completion = { [weak self] in print("done"); self?.didComplete() }
}
func doSomething() { self.doSomethingElse() }
}
Empty declarations should be written in empty braces ({}
), otherwise a comment should indicate the reason for the empty implementation.
Cause: Makes it clear that the declaration was meant to be empty and not just a missing TODO
.
- Preferred
extension Icon: Equatable {}
var didTap: () -> Void = {}
override func drawRect(rect: CGRect) {}
@objc dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
// do nothing; delegate method required to enable tracking mode
}
- Not Preferred
extension Icon: Equatable {
}
var didTap: () -> Void = { }
override func drawRect(rect: CGRect) {
}
@objc dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
}
Close braces (}
) should not have empty lines before it. For single line expressions enclosed in braces, there should be one space between the last statement and the closing brace.
Cause: Provides breathing room between declarations while keeping code compact.
- Preferred
class Button {
var didTap: (sender: Button) -> Void = { _ in }
func tap() {
self.didTap()
}
}
- Not Preferred
class Button {
var didTap: (sender: Button) -> Void = {_ in}
func tap() {
self.didTap()
}
}
Close braces (}
) unless on the same line as its corresponding open brace ({
), should be left-aligned with the statement that declared the open brace.
Cause: Close braces left-aligned with their opening statements visually express their scopes pretty well. This rule is the basis for the succeeding formatting guidelines below.
- Preferred
lazy var largeImage: UIImage = { () -> UIImage in
let image = // ...
return image
}()
- Not Preferred
lazy var largeImage: UIImage = { () -> UIImage in
let image = // ...
return image
}()
The get
and set
statement and their close braces (}
) should all be left-aligned. If the statement in the braces can be expressed in a single line, the get
and set
declaration can be inlined.
Cause: Combined with the rules on braces, this formatting provides very good consistency and scannability.
- Preferred
struct Rectangle {
// ...
var right: Float {
get {
return self.x + self.width
}
set {
self.x = newValue - self.width
}
}
}
struct Rectangle {
// ...
var right: Float {
get { return self.x + self.width }
set { self.x = newValue - self.width }
}
}
- Not Preferred
struct Rectangle {
// ...
var right: Float {
get
{
return self.x + self.width
}
set
{
self.x = newValue - self.width
}
}
}
struct Rectangle {
// ...
var right: Float {
get { return self.x + self.width }
set { self.x = newValue - self.width
print(self)
}
}
}
Cause: The return
statement provides enough clarity that lets us use the more compact form.
- Preferred
struct Rectangle {
// ...
var right: Float {
return self.x + self.width
}
}
- Not Preferred
struct Rectangle {
// ...
var right: Float {
get {
return self.x + self.width
}
}
}
if
, else
, switch
, do
, catch
, repeat
, guard
, for
, while
, and defer
statements should be left-aligned with their respective close braces (}
).
Cause: Combined with the rules on braces, this formatting provides very good consistency and scannability. Close braces left-aligned with their respective control flow statements visually express their scopes pretty well.
- Preferred
if array.isEmpty {
// ...
}
else {
// ...
}
or
if array.isEmpty {
// ...
} else {
// ...
}
Personally, I like the second way
- Not Preferred
if array.isEmpty
{
// ...
}
else
{
// ...
}
case
statements should be left-aligned with the switch
statement. Single-line case
statements can be inlined and written compact. Multi-line case
statements should be indented below case:
and separated with one empty line.
Cause: Reliance on Xcode's auto-indentation. For multi-line statements, separating case
s with empty lines enhance visual separation.
- Preferred
switch result {
case .Success:
self.doSomething()
self.doSomethingElse()
case .Failure:
self.doSomething()
self.doSomethingElse()
}
switch result {
case .Success: self.doSomething()
case .Failure: self.doSomethingElse()
}
- Not Preferred
switch result {
case .Success: self.doSomething()
self.doSomethingElse()
case .Failure: self.doSomething()
self.doSomethingElse()
}
switch result {
case .Success: self.doSomething()
case .Failure: self.doSomethingElse()
}
Cause: Do coding Swift way
- Preferred
if array.isEmpty {
// ...
}
- Not Preferred
if (array.isEmpty) {
// ...
}
Cause: The more nested scopes to keep track of, the heavier the burden of scanning code.
- Preferred
guard let strongSelf = self else {
return
}
// do many things with strongSelf
- Not Preferred
if let strongSelf = self {
// do many things with strongSelf
}
Naming rules are mostly based on Apple's naming conventions, since we'll end up consuming their API anyway.
Cause: Adopt Apple's naming rules for uniformity.
- Preferred
class ImageButton {
enum ButtonState {
// ...
}
}
- Not Preferred
class image_button {
enum buttonState {
// ...
}
}
Cause: Adopt Apple's naming rules for uniformity.
- Preferred
enum ErrorCode {
case Unknown
case NetworkNotFound
case InvalidParameters
}
struct CacheOptions : OptionSetType {
static let None = CacheOptions(rawValue: 0)
static let MemoryOnly = CacheOptions(rawValue: 1)
static let DiskOnly = CacheOptions(rawValue: 2)
static let All: CacheOptions = [.MemoryOnly, .DiskOnly]
// ...
}
- Not Preferred
enum ErrorCode {
case unknown
case network_not_found
case invalidParameters
}
struct CacheOptions : OptionSetType {
static let none = CacheOptions(rawValue: 0)
static let memory_only = CacheOptions(rawValue: 1)
static let diskOnly = CacheOptions(rawValue: 2)
static let all: CacheOptions = [.memory_only, .diskOnly]
// ...
}
Variables and functions should be in lowerCamelCase, including statics and constants. An exception is acronyms, which should be UPPERCASE.
Cause: Adopt Apple's naming rules for uniformity. As for acronyms, the readability makes keeping them upper-case worth it.
- Preferred
var webView: UIWebView?
var URLString: String?
func didTapReloadButton() {
// ..
}
- Not Preferred
var web_view: UIWebView?
var urlString: String?
func DidTapReloadButton() {
// ..
}
Avoid single-character names for types, variables, and functions. The only place they are allowed is as indexes in iterators.
Cause: There is always a better name than single-character names. Even with i
, it is still more readable to use index
instead.
- Preferred
for (i, value) in array.enumerate() {
// ... "i" is well known
}
- Not Preferred
for (i, v) in array.enumerate() {
// ... what's "v"?
}
Avoid abbreviations as much as possible. (although Acceptable Abbreviations and Acronyms are allowed such as min
/max
).
Cause: Clarity is prioritized over slight brevity.
- Preferred
let errorCode = error.code
- Not Preferred
let err = error.code
Cause: Clarity is prioritized over slight brevity. Also, the more specific the name, the less likely they are to collide with other symbols.
- Preferred
class Article {
var title: String
}
class NewsArticle {
var headlineTitle: String
}
- Not Preferred
class Article {
var text: String
// is this the title or the content text?
}
Cause: Saves a few seconds checking header declarations for the correct type.
- Preferred
var requestURL: NSURL
var sourceURLString: String
func loadURL(URL: NSURL) {
// ...
}
func loadURLString(URLString: String) {
// ...
}
- Not Preferred
var requestURL: NSURL
var sourceURL: String
func loadURL(URL: NSURL) {
// ...
}
func loadURL(URL: String) {
// ...
}
Cause: The extra suffix is redundant. It should be noted though that Objective-C protocols with the same name as an existing Objective-C class are bridged to Swift with a ~Protocol
suffix (e.g. NSObject
and NSObjectProtocol
). But they are irrelevant to this guideline as they are automatically generated by the Swift compiler.
- Preferred
class User {
// ...
}
enum Result {
// ...
}
protocol Queryable {
// ...
}
- Not Preferred
class UserClass {
// ...
}
enum ResultEnum {
// ...
}
protocol QueryableProtocol {
// ...
}
Cause: Reduce merge conflicts when dependencies change between branches.
- Preferred
import Foundation
import UIKit
import Alamofire
import Cartography
import SwiftyJSON
- Not Preferred
import Foundation
import Alamofire
import SwiftyJSON
import UIKit
import Cartography
All properties and methods should be grouped into the superclass/protocol they implement and should be tagged with // MARK: <superclass/protocol name>
. The rest should be marked as either // MARK: Public
, // MARK: Internal
, or // MARK: Private
.
Cause: Makes it easy to locate where in the source code certain properties and functions are declared.
- Preferred
// MARK: - BaseViewController
class BaseViewController: UIViewController, UIScrollViewDelegate {
// MARK: Internal
weak var scrollView: UIScrollView?
// MARK: UIViewController
override func viewDidLoad() {
// ...
}
override func viewWillAppear(animated: Bool) {
// ...
}
// MARK: UIScrollViewDelegate
@objc dynamic func scrollViewDidScroll(scrollView: UIScrollView) {
// ...
}
// MARK: Private
private var lastOffset = CGPoint.zero
}
Cause: Aesthetic. Gives breathing room between type declarations and function groups.
- Preferred
import UIKit
// MARK: - BaseViewController
class BaseViewController: UIViewController {
// MARK: Internal
weak var scrollView: UIScrollView?
// MARK: UIViewController
override func viewDidLoad() {
// ...
}
override func viewWillAppear(animated: Bool) {
// ...
}
// MARK: Private
private var lastOffset = CGPoint.zero
}
- Not Preferred
import UIKit
// MARK: - BaseViewController
class BaseViewController: UIViewController {
// MARK: Internal
weak var scrollView: UIScrollView?
// MARK: UIViewController
override func viewDidLoad() {
// ...
}
override func viewWillAppear(animated: Bool) {
// ...
}
// MARK: Private
private var lastOffset = CGPoint.zero
}
Cause: Makes it easy to locate where in the source code certain implementations are declared. public
and internal
declarations are more likely to be referred to by API consumers, so are declared at the top.
// MARK: Public
// MARK: Internal
- Class Inheritance (parent-most to child-most)
// MARK: NSObject
// MARK: UIResponder
// MARK: UIViewController
- Protocol Inheritance (parent-most to child-most)
// MARK: UITableViewDataSource
// MARK: UIScrollViewDelegate
// MARK: UITableViewDelegate
// MARK: Private
@
properties (@NSManaged
,@IBOutlet
,@IBInspectable
,@objc
,@nonobjc
, etc.)lazy var
properties- computed
var
properties - other
var
properties let
properties@
functions (@NSManaged
,@IBAction
,@objc
,@nonobjc
, etc.)- other functions
@
properties and functions are more likely to be referred to (such as when checking KVC keys or Selector
strings, or when cross-referencing with Interface Builder) so are declared higher.
In general, all Xcode warnings should not be ignored. These include things like using let
instead of var
when possible, using _
in place of unused variables, etc.
Comments should be answering some form of "why?" question. Anything else should be explainable by the code itself, or not written at all.
Cause: The best comment is the ones you don't need. If you have to write one be sure to explain the rationale behind the code, not just to simply state the obvious.
- Preferred
let leftMargin: CGFloat = 20
view.frame.x = leftMargin
@objc dynamic func tableView(tableView: UITableView,
heightForHeaderInSection section: Int) -> CGFloat {
return 0.01 // tableView ignores 0
}
- Not Preferred
view.frame.x = 20 // left margin
@objc dynamic func tableView(tableView: UITableView,
heightForHeaderInSection section: Int) -> CGFloat {
return 0.01 // return small number
}
Cause: Features are usually debugged and tested in the native language and translated strings are usually tested separately. This guarantees that all unlocalized texts are accounted for and easy to find later on.
- Preferred
self.titleLabel.text = "Date Today:" // TODO: localize
- Not Preferred
self.titleLabel.text = "Date Today:"
All Objective-C protocol
implementations, whether properties or methods, should be prefixed with @objc dynamic
Cause: Prevents horrible compiler optimization bugs.
- Preferred
@objc dynamic func scrollViewDidScroll(scrollView: UIScrollView) {
// ...
}
- Not Preferred
func scrollViewDidScroll(scrollView: UIScrollView) {
// ...
}
Cause: Xcode automatically generates this for us when we drag&drop from storyboard to viewcontroller
- Preferred
@IBOutlet private dynamic weak var closeButton: UIButton?
@IBAction private dynamic func closeButtonTouchUpInside(sender: UIButton) {
// ...
}
All @IBOutlet
s should be declared weak
. They should also be wrapped as Optional
, not ImplicitlyUnwrappedOptional
.
Cause: This guarantees safety even if subclasses opt to not create the view for the @IBOutlet
. This also protects against crashes caused by properties being accessed before viewDidLoad(_:)
.
- Preferred
@IBOutlet dynamic weak var profileIcon: UIImageView?
- Not Preferred
@IBOutlet var profileIcon: UIImageView!
Cause: This helps prevent pollution of XCode's auto-completion. In theory this should also help the compiler make better optimizations and build faster.
For library modules: all declarations should explicitly specify either public
, internal
, or private
.
Cause: Makes the intent clear for API consumers.
- Preferred
private let defaultTimeout: NSTimeInterval = 30
internal class NetworkRequest {
// ...
}
- Not Preferred
let defaultTimeout: NSTimeInterval = 30
class NetworkRequest {
// ...
}
For application modules: public
access is prohibited unless required by a protocol. The internal
keyword may or may not be written, but the private
keyword is required.
Cause: A public
declaration in an app bundle does not make sense. In effect, declarations are assumed to be either internal
or private
, in which case it is sufficient to just require private
explicitly.
- Preferred
private let someGlobal = "someValue"
class AppDelegate {
// ...
private var isForeground = false
}
- Not Preferred
public let someGlobal = "someValue"
public class AppDelegate {
// ...
var isForeground = false
}
Combined with the rules on declaration order, this improves readability when scanning code vertically*
- Preferred
@objc internal class User: NSManagedObject {
// ...
@NSManaged internal dynamic var identifier: Int
// ...
@NSManaged private dynamic var internalCache: NSData?
}
- Not Preferred
internal @objc class User: NSManagedObject {
// ...
@NSManaged dynamic internal var identifier: Int
// ...
private @NSManaged dynamic var internalCache: NSData?
}
Unless required, a variable/property declaration's type should be inferred from either the left or right side of the statement, but not both.
Cause: Prevent redundancy. This also reduces ambiguity when binding to generic types.
- Preferred
var backgroundColor = UIColor.whiteColor()
var iconView = UIImageView(image)
var lineBreakMode = NSLineBreakMode.ByWordWrapping
// or
var lineBreakMode: NSLineBreakMode = .ByWordWrapping
- Not Preferred
var backgroundColor: UIColor = UIColor.whiteColor()
var iconView: UIImageView = UIImageView(image)
var lineBreakMode: NSLineBreakMode = NSLineBreakMode.ByWordWrapping
When literal types are involved (StringLiteralConvertible
, NilLiteralConvertible
, etc), it is encouraged to specify the type explicitly and is preferrable over casting with as
directly.
Cause: Prevent redundancy. This also reduces ambiguity when binding to generic types.
- Preferred
var radius: CGFloat = 0
var length = CGFloat(0)
- Not Preferred
var radius: CGFloat = CGFloat(0)
var length = 0 as CGFloat // prefer initializer to casts
- Preferred
let badgeNumber = unreadItems.count
Checking if empty or not:
if sequence.isEmpty {
// ...
- Not Preferred
if sequence.count <= 0 {
// ...
- Preferred
let first = sequence.first
let last = sequence.last
- Not Preferred
let first = sequence[0]
let last = sequence[sequence.count - 1]
- Preferred
sequence.removeFirst()
sequence.removeLast()
- Not Preferred
sequence.removeAtIndex(0)
sequence.removeAtIndex(sequence.count - 1)
- Preferred
for i in sequence.indices {
// ...
}
- Not Preferred
for i in 0 ..< sequence.count {
// ...
}
- Preferred
let first = sequence.indices.first
let last = sequence.indices.last
- Not Preferred
let first = 0
let last = sequence.count - 1
- Preferred
for i in sequence.indices.dropLast(n) {
// ...
}
- Not Preferred
for i in 0 ..< (sequence.count - n) {
// ...
}
- Preferred
for i in sequence.indices.dropFirst(n) {
// ...
}
- Not Preferred
for i in n ..< sequence.count {
// ...
}
Clarity of intent, which in turn reduces programming mistakes (esp. off-by-one calculation errors).
In particular, this will cover the ever-debatable usage/non-usage of self
.
For all non-@noescape
and non-animation closures, accessing self
within the closure requires a [weak self]
declaration.
*Combined with the self
-requirement rule above, retain cycle candidates are very easy to spot. Just look for closures that access self
and check for the missing [weak self]
. *
- Preferred
self.request.downloadImage(
url,
completion: { [weak self] image in
self?.didDownloadImage(image)
}
)
- Not Preferred
self.request.downloadImage(
url,
completion: { image in
self.didDownloadImage(image) // hello retain cycle
}
)
Cause: While unowned
is more convenient (you don't need to work with an Optional
) than weak
, it is also more prone to crashes. Nobody likes zombies.
- Preferred
self.request.downloadImage(
url,
completion: { [weak self] image in
self?.didDownloadImage(image)
}
)
- Not Preferred
self.request.downloadImage(
url,
completion: { [unowned self] image in
self.didDownloadImage(image)
}
)
If the validity of the weak self
in the closure is needed, bind using the variable `self`
to shadow the original.
Cause: Write the nice looking code
- Preferred
self.request.downloadImage(
url,
completion: { [weak self] image in
guard let `self` = self else {
return
}
self.didDownloadImage(image)
self.reloadData()
self.doSomethingElse()
}
)
- Not Preferred
self.request.downloadImage(
url,
completion: { [weak self] image in
guard let strongSelf = self else {
return
}
strongSelf.didDownloadImage(image)
strongSelf.reloadData()
strongSelf.doSomethingElse()
}
)
See the LICENSE file for more info.