Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
/ swift-style-guide Public archive

**Archived** Style guide & coding conventions for Swift projects

License

Notifications You must be signed in to change notification settings

github/swift-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

This repository is no longer active.


A guide to our Swift style and conventions.

This is an attempt to encourage patterns that accomplish the following goals (in rough priority order):

  1. Increased rigor, and decreased likelihood of programmer error
  2. Increased clarity of intent
  3. Reduced verbosity
  4. Fewer debates about aesthetics

If you have suggestions, please see ourcontribution guidelines, then open a pull request. ⚡


Whitespace

  • Tabs, not spaces.
  • End files with a newline.
  • Make liberal use of vertical whitespace to divide code into logical chunks.
  • Don’t leave trailing whitespace.
    • Not even leading indentation on blank lines.

Preferlet-bindings overvar-bindings wherever possible

Uselet foo =…overvar foo =…wherever possible (and when in doubt). Only usevarif you absolutely have to (i.e. youknowthat the value might change, e.g. when using theweakstorage modifier).

Rationale:The intent and meaning of both keywords are clear, butlet-by-defaultresults in safer and clearer code.

Alet-binding guarantees andclearly signals to the programmerthat its value will never change. Subsequent code can thus make stronger assumptions about its usage.

It becomes easier to reason about code. Had you usedvarwhile still making the assumption that the value never changed, you would have to manually check that.

Accordingly, whenever you see avaridentifier being used, assume that it will change and ask yourself why.

Return and break early

When you have to meet certain criteria to continue execution, try to exit early. So, instead of this:

if n.isNumber{
// Use n here
}else{
return
}

use this:

guard n.isNumberelse{
return
}
// Use n here

You can also do it withifstatement, but usingguardis preferred, becauseguardstatement withoutreturn,breakorcontinueproduces a compile-time error, so exit is guaranteed.

Avoid Using Force-Unwrapping of Optionals

If you have an identifierfooof typeFooType?orFooType!,don't force-unwrap it to get to the underlying value (foo!) if possible.

Instead, prefer this:

ifletfoo=foo{
// Use unwrapped `foo` value in here
}else{
// If appropriate, handle the case where the optional is nil
}

Alternatively, you might want to use Swift's Optional Chaining in some of these cases, such as:

// Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call
foo?.callSomethingIfFooIsNotNil()

Rationale:Explicitif let-binding of optionals results in safer code. Force unwrapping is more prone to lead to runtime crashes.

Avoid Using Implicitly Unwrapped Optionals

Where possible, uselet foo: FooType?instead oflet foo: FooType!iffoomay be nil (Note that in general,?can be used instead of!).

Rationale:Explicit optionals result in safer code. Implicitly unwrapped optionals have the potential of crashing at runtime.

Prefer implicit getters on read-only properties and subscripts

When possible, omit thegetkeyword on read-only computed properties and read-only subscripts.

So, write these:

varmyGreatProperty:Int{
return4
}

subscript(index:Int)->T{
returnobjects[index]
}

…not these:

varmyGreatProperty:Int{
get{
return4
}
}

subscript(index:Int)->T{
get{
returnobjects[index]
}
}

Rationale:The intent and meaning of the first version are clear, and results in less code.

Always specify access control explicitly for top-level definitions

Top-level functions, types, and variables should always have explicit access control specifiers:

publicvarwhoopsGlobalState:Int
internalstructTheFez{}
privatefuncdoTheThings(things:[Thing]){}

However, definitions within those can leave access control implicit, where appropriate:

internalstructTheFez{
varowner:Person=Joshaber()
}

Rationale:It's rarely appropriate for top-level definitions to be specificallyinternal,and being explicit ensures that careful thought goes into that decision. Within a definition, reusing the same access control specifier is just duplicative, and the default is usually reasonable.

When specifying a type, always associate the colon with the identifier

When specifying the type of an identifier, always put the colon immediately after the identifier, followed by a space and then the type name.

classSmallBatchSustainableFairtrade:Coffee{...}

lettimeToCoffee:NSTimeInterval=2

funcmakeCoffee(type:CoffeeType)->Coffee{...}

Rationale:The type specifier is saying something about theidentifierso it should be positioned with it.

Also, when specifying the type of a dictionary, always put the colon immediately after the key type, followed by a space and then the value type.

letcapitals:[Country:City]=[sweden:stockholm]

Only explicitly refer toselfwhen required

When accessing properties or methods onself,leave the reference toselfimplicit by default:

privateclassHistory{
varevents:[Event]

funcrewrite(){
events=[]
}
}

Only include the explicit keyword when required by the language—for example, in a closure, or when parameter names conflict:

extensionHistory{
init(events:[Event]){
self.events=events
}

varwhenVictorious:()->(){
return{
self.rewrite()
}
}
}

Rationale:This makes the capturing semantics ofselfstand out more in closures, and avoids verbosity elsewhere.

Prefer structs over classes

Unless you require functionality that can only be provided by a class (like identity or deinitializers), implement a struct instead.

Note that inheritance is (by itself) usuallynota good reason to use classes, because polymorphism can be provided by protocols, and implementation reuse can be provided through composition.

For example, this class hierarchy:

classVehicle{
letnumberOfWheels:Int

init(numberOfWheels:Int){
self.numberOfWheels=numberOfWheels
}

funcmaximumTotalTirePressure(pressurePerWheel:Float)->Float{
returnpressurePerWheel*Float(numberOfWheels)
}
}

classBicycle:Vehicle{
init(){
super.init(numberOfWheels:2)
}
}

classCar:Vehicle{
init(){
super.init(numberOfWheels:4)
}
}

could be refactored into these definitions:

protocolVehicle{
varnumberOfWheels:Int{get}
}

funcmaximumTotalTirePressure(vehicle:Vehicle,pressurePerWheel:Float)->Float{
returnpressurePerWheel*Float(vehicle.numberOfWheels)
}

structBicycle:Vehicle{
letnumberOfWheels=2
}

structCar:Vehicle{
letnumberOfWheels=4
}

Rationale:Value types are simpler, easier to reason about, and behave as expected with theletkeyword.

Make classesfinalby default

Classes should start asfinal,and only be changed to allow subclassing if a valid need for inheritance has been identified. Even in that case, as many definitions as possiblewithinthe class should befinalas well, following the same rules.

Rationale:Composition is usually preferable to inheritance, and optinginto inheritance hopefully means that more thought will be put into the decision.

Omit type parameters where possible

Methods of parameterized types can omit type parameters on the receiving type when they’re identical to the receiver’s. For example:

structComposite<T>{

funccompose(other:Composite<T>)->Composite<T>{
returnComposite<T>(self,other)
}
}

could be rendered as:

structComposite<T>{

funccompose(other:Composite)->Composite{
returnComposite(self,other)
}
}

Rationale:Omitting redundant type parameters clarifies the intent, and makes it obvious by contrast when the returned type takes different type parameters.

Use whitespace around operator definitions

Use whitespace around operators when defining them. Instead of:

func<|(lhs:Int,rhs:Int)->Int
func<|<<A>(lhs:A,rhs:A)->A

write:

func<|(lhs:Int,rhs:Int)->Int
func<|<<A>(lhs:A,rhs:A)->A

Rationale:Operators consist of punctuation characters, which can make them difficult to read when immediately followed by the punctuation for a type or value parameter list. Adding whitespace separates the two more clearly.

Translations

About

**Archived** Style guide & coding conventions for Swift projects

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published