- Notifications
You must be signed in to change notification settings - Fork566
**Archived** Style guide & coding conventions for Swift projects
License
github/swift-style-guide
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A guide to our Swift style and conventions.
This is an attempt to encourage patterns that accomplish the following goals (inrough priority order):
- Increased rigor, and decreased likelihood of programmer error
- Increased clarity of intent
- Reduced verbosity
- Fewer debates about aesthetics
If you have suggestions, please see ourcontribution guidelines,then open a pull request. ⚡
- 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.
Uselet foo = …
overvar foo = …
wherever possible (and when in doubt). Only usevar
if you absolutely have to (i.e. youknow that the value might change, e.g. when using theweak
storage modifier).
Rationale: The intent and meaning of both keywords are clear, butlet-by-default results in safer and clearer code.
Alet
-binding guarantees andclearly signals to the programmer that its value will never change. Subsequent code can thus make stronger assumptions about its usage.
It becomes easier to reason about code. Had you usedvar
while still making the assumption that the value never changed, you would have to manually check that.
Accordingly, whenever you see avar
identifier being used, assume that it will change and ask yourself why.
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 withif
statement, but usingguard
is preferred, becauseguard
statement withoutreturn
,break
orcontinue
produces a compile-time error, so exit is guaranteed.
If you have an identifierfoo
of typeFooType?
orFooType!
, don't force-unwrap it to get to the underlying value (foo!
) if possible.
Instead, prefer this:
iflet foo= 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 callfoo?.callSomethingIfFooIsNotNil()
Rationale: Explicitif let
-binding of optionals results in safer code. Force unwrapping is more prone to lead to runtime crashes.
Where possible, uselet foo: FooType?
instead oflet foo: FooType!
iffoo
may 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.
When possible, omit theget
keyword on read-only computed properties andread-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.
Top-level functions, types, and variables should always have explicit access control specifiers:
publicvarwhoopsGlobalState:IntinternalstructTheFez{}privatefunc doTheThings(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 the type of an identifier, always put the colon immediatelyafter the identifier, followed by a space and then the type name.
classSmallBatchSustainableFairtrade:Coffee{...}lettimeToCoffee:NSTimeInterval=2func makeCoffee(type:CoffeeType)->Coffee{...}
Rationale: The type specifier is saying something about theidentifier soit should be positioned with it.
Also, when specifying the type of a dictionary, always put the colon immediatelyafter the key type, followed by a space and then the value type.
letcapitals:[Country:City]=[sweden: stockholm]
When accessing properties or methods onself
, leave the reference toself
implicit by default:
privateclassHistory{varevents:[Event]func rewrite(){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 ofself
stand out more in closures, and avoids verbosity elsewhere.
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) usuallynot a 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:Intinit(numberOfWheels:Int){self.numberOfWheels= numberOfWheels}func maximumTotalTirePressure(pressurePerWheel:Float)->Float{return pressurePerWheel* 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}}func maximumTotalTirePressure(vehicle:Vehicle, pressurePerWheel:Float)->Float{return pressurePerWheel* 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 thelet
keyword.
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 possiblewithin the class should befinal
as well, following the same rules.
Rationale: Composition is usually preferable to inheritance, and optingin to inheritance hopefully means that more thought will be put into the decision.
Methods of parameterized types can omit type parameters on the receiving type when they’re identical to the receiver’s. For example:
struct Composite<T>{…func compose(other:Composite<T>)->Composite<T>{returnComposite<T>(self, other)}}
could be rendered as:
struct Composite<T>{…func compose(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 operators when defining them. Instead of:
func<|(lhs:Int, rhs:Int)->Intfunc <|<<A>(lhs:A, rhs:A)->A
write:
func<|(lhs:Int, rhs:Int)->Intfunc <|<<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.
About
**Archived** Style guide & coding conventions for Swift projects
Resources
License
Code of conduct
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.