- API Design guidelines
- Tabs
- Comments and autogenerated code
- Semicolons
- Curly Braces
- Naming
- Immutability
- Access Control
- Closures
- Objective-C runtime
- Explicit references to self
- Optionals
- Implicit getters
- Omitting type parameters
- Syntactic sugar
- Struct initializers
- Structuring code
- Extensions
- Namespacing
- References
Strictly follow Swift 3 API Design Guidelines
- Use spaces instead of tabs. Use Xcode setting, that replaces tab with 4 spaces(default).
- Always try to limit Line length to 100 characters.
- End files with a newline
Remove autogenerated code and unused methods and variables. Don't write comments - code should be self-explanatory. Comments are only acceptable when they describe not obvious workaround in code, that can not be avoided or made more clear.
Do not use semicolons at end of the line.
Curly braces can be put on the same line as enclosing declaration, for example:
if foo != nil {
} else {
}
They can also be moved to the next line, if it makes code easier to read - mostly for long lines, for example
func extremelyAwesomeMethodWithMupltipleParameters(parameterOne: String,
andClosure closure: String -> Void)
{
}
Class, protocol and category names must consist of words and generally accepted abbreviations (Facebook - FB, etc.), each of which begins with a capital letter. Examples:
class ContactTableViewCell : UITableViewCell
class RefreshableDataSource
protocol AuthorizationDelegate
When picking a protocol name, always consider what your protocol is about. If it declares that type can be something else, use Convertible
word in a name, for example
protocol JSONConvertible
protocol APIFilterConvertible
If your protocol defines an action or capability, that can be performed on or by instance of your object, use -able or -ible suffix:
protocol Streamable
protocol Mappable
protocol MemberContentVisible
If your protocol serves as a data source or a delegate, you can end name of your protocol with DataSource
or Delegate
ending.
Variable names should begin with lower case letter. Use descriptive names to clarify your intent:
// Good:
let maximumPreviewCount = 5
//Bad
let MAX_PR_COUNT = 5
For functions and methods, prefer named parameters unless intent and context are completely clear. Follow Apple convention to always name first argument in the name of the method:
class Counter {
func combine(with: Counter) { ... }
func increment(byAmount: Int) { ... }
}
Typealiases should be short and meaningful. For example:
typealias MoneyAmount = Double
typealias ModelType
Generic types should start with letter T
, then U
, V
and so on. You can use different names to make usage of generics more clear, for example:
public struct CollectionViewSection<Item>: CollectionViewSectionInfo {}
Always prefer let
declarations over var
. It clearly sends a message, that value will not be changed. If you don't need a variable, use nameless binding like so:
_ = methodThatReturnsUnusedVariable()
Prefer value types over reference types. Use structs instead of classes when you don't need reference semantics. Using value types provides a lot of benefits, such as protection against changing from different owners. It also frees you from memory management, because value types are copied instead of passing by reference. And it also provides thread-safety for your objects.
If your classes don't need any inheritance, mark them final to let compiler know, that class will not be subclassed.
final class User
{
}
This provides perfomance improvements in code compilation and in runtime - Apple Swift Blog.
Declare properties and methods private
, when they should not be visible from outside of current file. Keep in mind, that private properties and methods are actually marked as final
by compiler, optimizing perfomance. Don't add modifiers, if they are already a default. For example:
// Not preferred
internal extension String {
var uppercaseString: String
}
// Preferred
extension String {
var uppercaseString: String
}
Use trailing closures, when intent is clear, and last parameter name is not relevant, for example:
// Not preferred
UIView.animate(withDuration:0.5, animations: {
view.alpha = 1
})
// Preferred
UIView.animate(withDuration:0.5) {
view.alpha = 1
}
Minimize parameter names that go inside closures to simplify closure syntax, for example:
// Not preferred
request.perform(success: { (responseObject, response) -> Void in
// Do something
})
// Preferred
request.perform(success: { responseObject, _ in
// Do something
})
Do not bluntly use weak self
in every closure - figure out, where it is really needed - most of the time it happens when closure is stored on your object. In previous examples with UIView animation it is not needed. And even if you do have retain cycles, if your object existance is guaranteed, use [unowned self]
instead of weak to minimize optionals. Remember, that self is not the only one object, that can be part of retain cycles. If you have multiple arguments in capture list, remember to put weak or unowned before each one, for example:
let foo = Foo()
foo.performStuff { [weak self, unowned foo] in
self?.method()
foo.method()
}
You can omit parameter names in closures, if it's absolutely clear, what closure parameter is, for example:
let artworkDictionaryArray : [[String: AnyObject]] = ...
// Not preferred:
let parsedArtworksArray = artworkDictionaryArray.map({ dictionary in
return Artwork(dictionary: dictionary)
})
// Preferred:
let parsedArtworksArray = artworkDictionaryArray.map { Artwork(dictionary: $0) }
As shown above, if your line is short, you can have curly braces on the same line.
Don't include objective-c runtime unless absolutely necessary. For example, Swift protocols do not allow optional methods. Instead of declaring protocol @objc, try to split protocols into several ones. Treat your protocols like traits, that may or may not be present. For example:
// Not Preferred
@objc protocol MovementAbilities {
optional var speed: CGFloat { get }
optional var maximumDepth : CGFloat { get }
}
class User: MovementAbilities {
//...
}
// Preferred
protocol Runner {
var speed: CGFloat { get }
}
protocol Swimmer {
var maximumDepth : CGFloat { get }
}
class User: Runner, Swimmer {
//...
}
Try to work with compile-time representations of data types instead of runtime. Avoid using dynamic
attributes(unless it's CoreData, where it's required).
Use Swift native types instead of Objective-C ones whenever possible. For example, use String
instead of NSString
, and Int
instead of NSNumber
.
Only use explicit self
when compiler requires you to, for example in constructors
struct Person {
let firstName: String
let lastName : String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
or in closures.
Avoid using force unwrapping. Use optional chaining or if let
bindings to unwrap optional values.
var name: String?
var age: String?
if let name = name, age = age, age >= 13 {
// ...
}
foo?.callSomethingIfFooIsNotNil()
Use nil-coalescing operator to avoid using force-unwrapping or checking for nil, for example:
if user?.isValid ?? false {
// .. Do something
}
Use guard construct to break/return early.
func makePaymentForUser(user: User) {
guard let creditCard = user.creditCard else {
return
}
creditCard.withdrawAmount(500000)
}
There are several cases, where usage of force unwrapping is allowed. For example, IBOutlets are guaranteed to exist, and you need to crash application if they don't, so this is allowed:
class ProfileViewController : UIViewController {
@IBOutlet weak var firstNameTextField : UITextField!
}
Another use case is unit tests, if you have your "system under test" created in setup method:
class UserTestCase : XCTestCase {
var sut : User!
func setUp() {
super.setUp()
sut = User.fixture()
}
func testUser() {
XCTAssert(sut.isValid())
}
}
Read-only computed properties don't need explicit getter:
// Not Preferred
var quality : CGFloat {
get {
return 5.0
}
}
// Preferred
var quality : CGFloat {
return 5.0
}
Omit type parameters, when they can be inferred by compiler, for example:
// Not preferred:
var color : UIColor = UIColor.clear
view.backgroundColor = UIColor.clear
// Preferred:
var color = UIColor.clear
view.backgroundColor = .clear
Prefer shortcut versions of type declarations over full generics syntax:
// Not preferred:
let models : Array<String>
//Preferred:
let models: [String]
Use native Swift initializers rather then legacy CGGeometry constructors
// Not preferred:
let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)
// Preferred:
let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)
Prefer struct-scope constants like Int.max
to legacy ones like CGRectZero
.
When conforming to a protocol, create extension with conformance methods:
class MyViewController: UIViewController {
}
extension MyViewController : UIScrollViewDelegate {
// Scroll View delegate methods
}
Add pragma marks to make particular code block clear:
class MyViewController : UIViewController {
// MARK: - View lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// ...
}
// MARK: - Actions
@IBAction func buttonTapped() {
}
}
In general, try to keep files simple. Every file, that has more than 200 lines of code, needs to have a valid reason to be like that. If your source file size is more than 500 lines, this should be considered a technical debt, and be split into several files.
When picking extension file name, consider functionality you are providing. For example, if you write extension on UIImage, that will provide placeholders, name it UIImage+Placeholders
. If it is hard to determine, which functionality is added, using one word, name it with +Extensions
suffix like so: UIImage+Extensions
.
You can use namespacing to make code usage more clear. Until proper namespaces are added to Swift, use enums for pure namespacing purposes:
enum API {
enum Users {
static func get() -> [User]
}
}
let users = API.Users.get()