- You declare constants with the
letkeyword and variables with thevarkeyword. - In practice, it is rare that you will need a type annotation. It may be useful if you are declaring a variable and no initial value is provided.
- To use string interpolation, wrap the variable name in parentheses and escape it with a backslash before the opening parenthesis.
- You can nest multiline comments.
- Both integers and floats can be padded with extra zeroes and can contain
_characters to help with readability.
- Prefer
Intfor even non-negative values. This means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. - Conversion between integer and floating-point must be explicit, regardless of the direction. An exception is made for numeric literals, which do not have an explicit type in and of themselves.
- You can decompose tuples. If you only need some parts of the tuple's values, ignore parts of the tuple with the
_character when decomposing. - If the elements in a tuple are unnamed, you can access them with index numbers starting at zero, e.g.
tupleName.0. If they are named, you can access them by their element names, e.g.tupleName.firstElementName. - Tuples are not suited for the creation of complex data structures. Use them primarily for returning multiple values from a function.
- An optional lets you indicate the absence of a value for any type at all, without the need for special constants like
NSNotFound. - You can only assign
nilto an optional variable. You cannot use it with nonoptional constants and variables. - The value
nilis not the same in Objective-C as it is in Swift. In Swift,nilis not a pointer like it is in Objective-C. Instead, it is an absence of a value of a certain type. - Once you're sure that an optional does contain a value, you can access that value by appending
!to the end of the optional's name. This is called forced unwrapping of its value. - Optional binding, written as
let constantName = someOptionalorvar constantName = someOptional, can be used withifandwhilestatements to check for a value inside an optional and extract it as a constant in a single action. - If the conversion that is part of optional binding is successful, then the constant is initialized with the value inside the optional, and there is no need to use the
!suffix. - An implicitly unwrapped optional has a
!instead of a?after the type that you want to make optional. Use this if an optional will always have a value after it's first set, and you want to remove the need to check and unwrap the optional's value on each access. - If you try to access an implicitly unwrapped optional when it doesn't contain a value, you trigger a runtime error, much like if you place a
!after a normal optional missing a value.
- The assignment operator in Swift does not return a value, so you cannot accidentally use
=when you mean==. - The
%operator is the remainder operator, and not a modulo operator. - Given a negative first operand, the remainder operator can yield a negative value. But the sign of the second operand for the remainder operator is ignored, so
a % banda % -balways yield the same answer. - The remainder operator can also accept a second operand that is a floating point number.
- It is recommended that you use the prefix version of the increment and decrement operators, unless you need the specific behavior of their postfix forms.
- The compound assignment operators do not return a value.
- The identity operators
===and!==test whether two object references both refer to the same object instance.
- The nil coalescing operator
(a ?? b)unwraps an optionalaif it contains a value, or returns a default valuebifaisnil. Ifais notnil, thenbis not evaluated.
- The closed range operator
a...bis inclusive ofb, while the half-open range operatora..<bis exclusive ofb.
- The
Stringtype is a value type, and such a value is copied when it is passed to a function or method, or when it is assigned to a constant or value.
- You can create a stand-alone character constant or variable from a single-character string literal by providing a
Charactertype annotation.
- A string literal can interpolate not just constants, variables, and literals, but expressions such as
\(Double(multiplier) * 2.5).
- A string literal can include an arbitrary Unicode scalar as
\u{n}, wherenis between one and eight hexadecimal digits, such as"\u{2665}". - Every
Characterinstance is a single extended grapheme cluster, which is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character. - The use of extended grapheme clusters for
Charactervalues means that string concatenation and modification may not always affect the character count of aStringinstance.
- Two
StringorCharactervalues are considered equivalent if their extended grapheme clusters are canonically equivalent, meaning they have the same linguistic meaning and appearance.
- Methods
utf8andutf16return code units for UTF-8 and UTF-16, while methodunicodeScalarsreturns 21-bitUnicodeScalarvalues, which is equivalent to UTF-32 encoding.
- Arrays and dictionaries assigned to variables are mutable, while arrays and dictionaries assigned to constants are immutable.
- The type of values stored by an array is specified by an explicit type annotation or type inference, and does not have to be a class type.
- To specify the type of an array, prefer the shorthand form
[ElementType]over the full formArray<ElementType>. - Thanks to type inference, you don't have to write the type of an array if you're initializing it with a literal containing values of the same type.
- You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing.
- The
removeAtIndexandremoveLastmethods return the removed item. - Use the global
enumeratefunction to iterate over tuples containing each item and its corresponding index. - To initialize an empty array, use the syntax
[ElementType](). If the context provides type information about an array variable, you can assign it simply[].
- To specify the type of a dictionary, prefer the shorthand form
[KeyType: ValueType]over the full formDictionary<KeyType, ValueType>. - Thanks to type inference, you don't have to write the type of a dictionary if you're initializing it with a literal containing keys of the same type, and values of the same type.
- Unlike using subscript syntax, method
updateValue(forKey:)returns the old value after performing an update. It returns an optional value of the dictionary's value type. - You can also use subscript syntax to remove a key-value pair from a dictionary by assigning a value of
nilfor that key. - If you need to use a dictionary's keys or values with an API that takes an
Arrayinstance, initialize a new array with thekeysorvaluesproperty. - To initialize an empty dictionary, use the syntax
[KeyType: ValueType](). If the context provides type information about a dictionary variable, you can assign it simply[:]. - Any type conforming to protocol
Hashablecan be used as a dictionary key. All of Swift's basic types are hashable by default, excluding enumeration member values with associated values.
- If you don't need access to the current value during each iteration of a
for-inloop, use the_character in place of a loop variable. - Each item in the dictionary is returned as a
(key, value)tuple when the dictionary is iterated over usingfor-in, and you can decompose that tuple's members as explicitly named constants.
- Every
switchstatement must be exhaustive, meaning every possible value must be matched by a case. If this is not appropriate, you can usedefaultto specify a catch-all case. - Unlike
switchstatements in C and Objective-C,switchstatements in Swift do not fall through the bottom of each case and into the next one by default. - Multiple matches for a single
switchcase can be separated by commas, and can be written over multiple lines if the list is long. - Use tuples to test multiple values in the same
switchstatement, where each element can be tested against a different value or range of values. Or use the_identifier to match any possible value. - A
switchcase can employ value binding to bind the value or values it matches to temporary consonants or variables for use in the body of the case. - A
switchcase can use awhereclause to check for additional conditions.
- A
switchcase that is empty or contains only a comment is a compile-time error. Use abreakstatement, which ends execution of a case immediately, to ignore such a case. - A
switchstatement does not fall through the bottom of one case and into the next one, unless that case ends with thefallthroughkeyword. - The
fallthroughkeyword does not check the case conditions for the nextswitchcase that it causes execution to fall into. - You can mark a loop or
switchstatement with a statement label, and use this label with thebreakorcontinuestatement to end or continue the execution of the labeled statement.
- Functions without a defined return type return a special value of type
Void, which is simply an empty tuple that can be written as(). - If the function returns a tuple, and its return type specifies names for the tuple values, then the tuple's members do not need to be named where the tuple is returned from the function.
- Precede a local parameter name with an external parameter name if you want users of your function to provide parameter names when they call your function.
- If you provide an external parameter name for a parameter, that external name must always be used when you call the function.
- Use external parameter names whenever the purpose of a function's arguments would be unclear to someone reading your code for the first time.
- Prefix a local parameter name with
#to generate an external parameter with the same name. - Place parameters with default values at the end of a function's parameter list. This ensures that all calls to the function use the same order for their non-default arguments.
- Swift provides an automatic external variable name for any parameter that has a default value, ensuring that the argument for that parameter is clear in purpose if a value is provided.
- A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters.
- Variable parameters give you a new modifiable copy of the parameter's value for your function to use. They exist only for the lifetime of that function call.
- You can only pass a variable as the argument for a parameter with the
inoutkeyword, and you must prefix the variable name with&.
- The function type is made up of the parameter types and the return type of a function.
- To use a function type as the return type of another function, write a complete function type immediately after the return arrow of the returning function.
- An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.
- Global functions are closures that have a name and do not capture any values, while nested functions are closures that have a name and can capture values from their enclosing function.
- Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent.
- The
inkeyword indicates that the definition of the closure's parameters and return type has finished, and that the body of the closure is about to begin. - If Swift can infer the parameter types and return types of a closure, such as when it's passed to a method, then all the types can be omitted, as well as the enclosing parentheses and the return arrow.
- It is always possible to infer the parameter types and return type when passing a closure to a function as an inline closure expression.
- Single-expression closures can implicitly return the result of their single expression by omitting the
returnkeyword from their declaration. - Swift automatically provides shorthand argument names
$0,$1, etc. These let you omit the closure's argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type.
- If a closure expression is provided as the function's only argument and you provide that expression as a trailing closure, you do not need to write
()after the function's name when you call the function. - Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line.
- In closures, Swift determines what should be captured by reference and what should be copied by value. It also handles all memory management for disposing captured values when no longer needed.
- If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance.
- Functions and closures are reference types, and so by assigning a closure to two different constants or variables, both of those constants or variables will refer to the same closure.
- Unlike C and Objective-C, enumeration members do not assume integer values. Instead, they are fully-fledged values in their own right with an explicitly-defined type.
- To define multiple member values on a single line, prefix them with
caseand separate them by commas. - Once the enumeration type of a variable is known, you can drop the enumeration type name when assigning its value, such as
directionToHead = .East.
- A switch statement must be exhaustive when considering the members of an enumeration. Use a
defaultcase to cover any members that are not addressed explicitly.
- Enumerations can serve as discriminated unions or tagged unions, where they can store associated values of any given type, and the value types can be different for each enumeration member.
- Each enumeration member defines only the type of associated values, but not actual values themselves.
- Extract each associated value as a constant (using
let) or as a variable (usingvar) for use within thecasebody of aswitchstatement. - If all of the associated values for a enumeration member are extracted as constants, or if all are extracted as variables, you can place a single
varorletannotation before the member name.
- Unlike associated values, enumeration members with raw values are all of the same type (constrained to strings, characters, integer, or floating-point number types), come prepopulated, and the values must be unique.
- When integers are used for raw values, they auto-increment if no value is specified for some of the enumeration members.
- Use
toRawandfromRawto convert between enumeration members and raw values. The latter returns an optional enumeration member, for when no member with the given raw value is found.
- Unlike structures, classes can use inheritance, participate in type casting, have deinitializers, and participate in reference counting.
- Unlike Objective-C, Swift allows you to set sub-properties of a structure property directly.
- All structures have an automatically-generated memberwise initializer, which allows initializing the properties of an instance by name.
- A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function.
- All the basic types in Swift are value types, and are implemented as structures.
- Classes are reference types, which are not copied when they are assigned to a variable or constant, or when they are passed to a function.
- Consider value types for simple collections of data, any properties are themselves value types, and the structure does not need to inherit properties or behavior from another type.
- Unlike
NSString,NSArray, andNSDictionaryin Foundation, theString,Array, andDictionarytypes in Swift are implemented as structures. - Swift only performs an actual copy of such types when it is absolutely necessary, and you should not avoid assignment to try and preempt this optimization.
- You can set and then modify the initial value for a stored property during initialization, even if it is a constant.
- When an instance of a value type is declared as constant using
let, then all of its properties are constant, and you cannot modify even those properties that are declared usingvar. - A lazy stored property is prefaced by the
lazykeyword, and its initial value is not calculated until the first time that it is used. - Swift unifies the concepts of properties and instance variables from Objective-C into a single property declaration. A property does not have a corresponding instance variable, and the backing store for a property is not accessed directly.
- Classes, structures, and enumerations can define computed properties, which don't actually store a value, but instead provide a getter and an optional setter.
- If a computed property's setter does not define a name for the new value to be set, a default name of
newValueis used. - You must declare a read-only computed property with the
varkeyword, because its value is not fixed. Theletkeyword is only used for constant properties, to indicate that their values cannot change. - You can simplify the declaration of a read-only computed property by removing the
getkeyword and its braces.
- The
willSetproperty observer is passed the new property value as a constant parameter. If you omit the parameter name, it will assume the default parameter name ofnewValue. - The
didSetproperty observer is passed the old property value as a constant parameter. If you omit the parameter name, it will assume the default parameter name ofoldValue. - If you assign a value to a property within its own
didSetobserver, the new value that you assign will replace the one that was just set.
- Global constants and variables are always computed lazily, similar to lazy stored properties. But local constants and variables are never computed lazily.
- A type property belongs to the type itself, and not any one instance. A constant type property is similar to a static constant in C, while a variable type property is similar to a static variable in C.
- Unlike stored instance properties, stored type properties must always have a default value. This is because the type itself doesn't have an initializer that can assign a value to such a property at initialization time.
- You define type properties for value types with the
statickeyword, and type properties for class types with theclasskeyword.
Methods are functions that are associated with a particular type.
- As in Objective-C, the name of a method in Swift typically refers to the method’s first parameter using a preposition such as
with,for, orby. - Unlike functions, the first parameter name in a method has a local parameter name by default, and the second and subsequent parameter names have both local and external parameter names by default.
- You can provide an external parameter name for the first parameter either explicitly or by prefixing the
#symbol, and suppress the external names of subsequent parameters by using the_symbol. - An instance method has implicit access to all other instance methods and properties of that type, but you can use
selfto refer to a property of the instance instead of an equivalent parameter name. - To modify the values of a value type, such as a structure or enumeration, its method must be declared as
mutating. Any changes made are written back when the method ends. - Mutating methods can assign an entirely new instance to the implicit
selfproperty. For example, a mutating method of an enumeration can setselfto be a different member of the same enumeration.
- Unlike Objective-C, in Swift you can define type-level methods for all classes, structures, and enumerations.
- Subscript definitions using the
subscriptkeyword can be read-write or read-only. This behavior is communicated by a getter and a setter method in the same way as for computed properties. - Like with computed properties, you can drop the
getkeyword for read-only subscripts, and the setter can use a default parameter namednewValueif no parameter is specified.
- Subscripts can return an optional type to model the fact that a value will not exist for every parameter value, such as an index or key.
- Subscripts can take any number of parameters of any type, and return any type. They can use variable parameters and variadic parameters, but cannot use
inoutparameters or provide default parameter values. - Subscript overloading allows you to define multiple subscript implementations, and a caller will invoke the appropriate one based on the types of the value or values between the braces.
- Swift classes do not inherit from a universal base class.
- To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the
overridekeyword. This not only clarifies, but guards against errors. - An overridden subscript for
someIndexcan access the superclass version of the same subscript assuper[someIndex]from within the overriding subscript implementation. - You can provide a custom getter or setter to override any inherited property, regardless of whether the inherited property is implemented as a stored or computed property at source.
- You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override, but you cannot present an inherited read-write property as a read-only property.
- If you provide a setter as part of a property override, you must also provide a getter for that override. Simply return
super.somePropertyif you don't want to modify its value. - You cannot add property observers defined by
willSetordidSetto inherited constant stored properties or inherited read-only computed properties, because their values cannot be set. - You cannot provide both an overriding setter and an overriding property observer for the same property. Instead, simply observe any value changes from within the custom setter.
- Put the modifier
finalbefore the introducer keyword of a method, property, or subscript to prevent it from being overridden. - Put the modifier
finalbefore theclasskeyword in a class definition to prevent subclassing.