2021-01-31 11:05:37 +01:00
|
|
|
# Swift / SwiftUI
|
|
|
|
|
|
|
|
- Statically Typed
|
|
|
|
|
|
|
|
[Building for Mac with VBox](https://medium.com/@twister.mr/installing-macos-to-virtualbox-1fcc5cf22801)
|
|
|
|
|
|
|
|
## Basics
|
|
|
|
|
|
|
|
### Macro
|
|
|
|
|
|
|
|
```swift
|
|
|
|
#if DEBUG
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
// contents compiled only if in DEBUG build
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
#endif
|
|
|
|
```
|
|
|
|
|
|
|
|
### Comments
|
|
|
|
|
|
|
|
```swift
|
|
|
|
// single line comment
|
|
|
|
|
|
|
|
/*
|
|
|
|
multi line comment
|
|
|
|
*/
|
|
|
|
```
|
|
|
|
|
|
|
|
### Variables
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var variable = value // implicit variable init (auto-determine type)
|
|
|
|
var variable: Type = value // explicit variable init
|
|
|
|
var variable: Type? = value // explicit nullable variable init
|
|
|
|
```
|
|
|
|
|
|
|
|
### Constants
|
|
|
|
|
|
|
|
```swift
|
|
|
|
let CONSTANT = value // constant init (value can be assigned at runtime)
|
|
|
|
```
|
|
|
|
|
|
|
|
### Console Output
|
|
|
|
|
|
|
|
```swift
|
|
|
|
print() // empty line
|
|
|
|
print(variable)
|
|
|
|
print("string")
|
|
|
|
```
|
|
|
|
|
|
|
|
## Strings
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var string "Text: \(<expr>)" // string interpolation
|
|
|
|
var string = "Hello" + "There" // string concatenation
|
|
|
|
|
|
|
|
var multilineString = """Use double quotes trice
|
|
|
|
to make a string span multiple lines"""
|
|
|
|
```
|
|
|
|
|
|
|
|
## Array
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var array = ["firstItem", "secondItem", ...]
|
|
|
|
var array = [Type()] // init empty homogeneous array
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
array[index] // value access
|
2021-01-31 11:05:37 +01:00
|
|
|
array[index] = value // value update
|
|
|
|
|
|
|
|
array.append(item) // add item to the end
|
|
|
|
array.contains(item) // membership check
|
|
|
|
array.sort() // in place sort
|
|
|
|
|
|
|
|
|
|
|
|
// Heterogeneous Array
|
|
|
|
var list: Any = ["string", 47, ...] // cannot access with [index]
|
|
|
|
var list: Any = [] // init empty heterogeneous array
|
|
|
|
```
|
|
|
|
|
|
|
|
## Tuple
|
|
|
|
|
|
|
|
A **tuple** type is a comma-separated list of types, enclosed in parentheses.
|
|
|
|
|
|
|
|
It's possible to use a tuple type as the return type of a function to enable the function to return a single tuple containing multiple values.
|
|
|
|
It's possible to name the elements of a tuple type and use those names to refer to the values of the individual elements.
|
|
|
|
An element name consists of an identifier followed immediately by a colon (:).
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var tuple: (Type, Type) = (value, value) // explicit type
|
|
|
|
var tuple = (value, value) // implicit type
|
|
|
|
tuple.0 // item access
|
|
|
|
|
|
|
|
// named elements
|
|
|
|
var tuple = (name1: value1, name2: value2, ...) // tuple init
|
|
|
|
tuple = (value1, value2) // names are inferred
|
|
|
|
tuple.name1 // item access
|
|
|
|
```
|
|
|
|
|
|
|
|
### Tuple Decomposition
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var tuple = (value1, value2)
|
|
|
|
var (var1, var2) = tuple // var1 = value1, var2 = value2
|
|
|
|
```
|
|
|
|
|
|
|
|
## Type Identifier
|
|
|
|
|
|
|
|
```swift
|
2021-09-20 19:35:32 +02:00
|
|
|
typealias Point = (Int, Int)
|
2021-01-31 11:05:37 +01:00
|
|
|
var origin: (0, 0)
|
|
|
|
```
|
|
|
|
|
|
|
|
## Dictionary
|
|
|
|
|
|
|
|
```swift
|
|
|
|
var dict = [
|
|
|
|
"key": "value",
|
|
|
|
...
|
|
|
|
]
|
|
|
|
|
|
|
|
var dict = [Type: Type]() // init empty dict
|
|
|
|
|
|
|
|
dict[key] // value access
|
|
|
|
dict[key] = value // value update
|
|
|
|
```
|
|
|
|
|
|
|
|
## Expressions & Operators
|
|
|
|
|
|
|
|
### Primary Expressions
|
|
|
|
|
|
|
|
| Syntax | Operation |
|
|
|
|
|---------------------|---------------------------------------------------------------------|
|
2021-09-20 19:35:32 +02:00
|
|
|
| x`.`m | access to member `m` of object `x` ("." --> member access operator) |
|
2021-01-31 11:05:37 +01:00
|
|
|
| x`(...)` | method invocation ("()" --> method invocation operator) |
|
2021-09-20 19:35:32 +02:00
|
|
|
| x`[...]` | array access and indicization |
|
2021-01-31 11:05:37 +01:00
|
|
|
| `new` T(...) | object instantiation |
|
|
|
|
| `x!` | declare x as not nil |
|
|
|
|
|
|
|
|
### Unary Operators
|
|
|
|
|
|
|
|
| Operator | Operation |
|
|
|
|
| --------- | --------------- |
|
|
|
|
| `+`x | identity |
|
|
|
|
| `-`x | negation |
|
|
|
|
| `!`x | logic negation |
|
|
|
|
| `~`x | binary negation |
|
|
|
|
| `++`x | pre-increment |
|
|
|
|
| `--`x | pre-decrement |
|
|
|
|
| x`++` | post-increment |
|
|
|
|
| x`--` | post decrement |
|
2021-09-20 19:35:32 +02:00
|
|
|
| `(type)`x | explicit casting |
|
2021-01-31 11:05:37 +01:00
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
### Mathematical Operators
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
| Operator | Operation |
|
|
|
|
| -------- | ----------------------------------------------------- |
|
|
|
|
| x `+` y | addition, string concatenation |
|
|
|
|
| x `-` y | subtraction |
|
|
|
|
| x `*` y | multiplication |
|
|
|
|
| x `/` y | integer division, **always** returns an `int` |
|
|
|
|
| x `%` y | modulo, remainder |
|
|
|
|
| x `<<` y | left bit shift |
|
2021-09-20 19:35:32 +02:00
|
|
|
| x `>>` y | right bit shift |
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
### Relational Operators
|
|
|
|
|
|
|
|
| Operator | Operation |
|
|
|
|
|----------|----------------------------------------|
|
|
|
|
| x `<=` y | less or equal to |
|
|
|
|
| x `>` y | greater than |
|
|
|
|
| x `>=` y | greater or equal to |
|
|
|
|
| x `is` T | `true` if `x` is an object of type `T` |
|
|
|
|
| x `==` y | equality |
|
|
|
|
| `!`x | inequality |
|
|
|
|
|
|
|
|
### Logical Operators
|
|
|
|
|
|
|
|
| Operator | Operation | Name |
|
|
|
|
|--------------|-------------------------------------------------------|------------------|
|
|
|
|
| `~`x | bitwise NOT |
|
|
|
|
| x `&` y | bitwise AND |
|
|
|
|
| x `^` y | bitwise XOR |
|
|
|
|
| x `|` y | bitwise OR |
|
|
|
|
| x `&&` y | evaluate `y` only if `x` is `true` |
|
|
|
|
| x `||` y | evaluate `y` only if `x` is `false` |
|
|
|
|
| x `??` y | evaluates to `y` only if `x` is `nil`, `x` otherwise | nil coalescing |
|
|
|
|
| x`?.`y | stop if `x == nil`, evaluate `x.y` otherwise | nil conditional |
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
### Assignment
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
| Operator | Operation |
|
|
|
|
|-----------|------------------------|
|
|
|
|
| x `+=` y | x = x + y |
|
|
|
|
| x `-=` y | x = x - y |
|
|
|
|
| x `*=` y | x = x * y |
|
|
|
|
| x `/=` y | x = x / y |
|
|
|
|
| x `%=` y | x = x % y |
|
|
|
|
| x `<<=` y | x = x << y |
|
|
|
|
| x `>>=` y | x = x >> y |
|
|
|
|
| x `&=` y | x = x & y |
|
|
|
|
| x `|=` y | x = x | y |
|
|
|
|
| x `^=` y | x = x ^ y |
|
|
|
|
| x `??=` y | if (x == nil) {x = y} |
|
|
|
|
|
|
|
|
### Conditional Operator
|
|
|
|
|
|
|
|
`<condition> ? <return_if_condition_true> : <return_if_condition_false>;`
|
|
|
|
|
|
|
|
### Nil Checks
|
|
|
|
|
|
|
|
```swift
|
|
|
|
variable ?? value
|
|
|
|
// same as
|
|
|
|
if(variable == nil) { variable = value }
|
|
|
|
```
|
|
|
|
|
|
|
|
## If-Else
|
|
|
|
|
|
|
|
```swift
|
|
|
|
if condition {
|
|
|
|
// code here
|
|
|
|
} else if condition {
|
|
|
|
//code here
|
|
|
|
} else {
|
|
|
|
// code here
|
|
|
|
}
|
|
|
|
|
|
|
|
if let var0 = var1 { /* statements */ }
|
|
|
|
// same as
|
|
|
|
let var0 = var1
|
|
|
|
if var0 != nil { /* statements */ }
|
|
|
|
```
|
|
|
|
|
|
|
|
### Switch
|
|
|
|
|
|
|
|
```swift
|
|
|
|
switch <value> {
|
|
|
|
case <pattern/key>:
|
|
|
|
// code here
|
|
|
|
break // can be implicit
|
|
|
|
|
|
|
|
case key where <condition_on_key>:
|
|
|
|
// code here
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
// code here
|
|
|
|
break
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Loops
|
|
|
|
|
|
|
|
### For Loop
|
|
|
|
|
|
|
|
```swift
|
|
|
|
// range based for
|
|
|
|
for i in start...end { /* statements */ } // end included
|
|
|
|
for i in start..<end { /* statements */ } // end excluded
|
|
|
|
for _ in start...end
|
|
|
|
|
|
|
|
for item in sequence {
|
|
|
|
// code here
|
|
|
|
}
|
|
|
|
|
|
|
|
for (key, value) in dict {
|
|
|
|
// code here
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### While Loop
|
|
|
|
|
|
|
|
```swift
|
|
|
|
while condition {
|
|
|
|
// code here
|
|
|
|
}
|
|
|
|
|
|
|
|
// "do"..while
|
|
|
|
repeat {
|
|
|
|
// code here
|
|
|
|
} while condition
|
|
|
|
```
|
|
|
|
|
|
|
|
## Functions
|
|
|
|
|
|
|
|
```swift
|
|
|
|
// "void function"
|
|
|
|
func funcName(param: Type, ...) {
|
|
|
|
// code here
|
|
|
|
}
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
func funcName(param: Type = defaultValue, ...) -> Type {
|
2021-01-31 11:05:37 +01:00
|
|
|
//code here
|
|
|
|
return <expression>
|
|
|
|
}
|
|
|
|
|
|
|
|
func funcName(param: Type) -> Type {
|
|
|
|
<expression> // implicit return
|
|
|
|
}
|
|
|
|
|
|
|
|
// func call MUST have parameter's names
|
|
|
|
funcName(param: value, ...)
|
|
|
|
|
|
|
|
// multiple return values
|
|
|
|
func funcMultipleParameters(param: Type) -> (retVal1: Type, retVal2: Type) {
|
|
|
|
//code here
|
|
|
|
|
|
|
|
return (<expression>, <expression>)
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = funcMultipleReturns(param: value)
|
2021-09-20 19:35:32 +02:00
|
|
|
result.retVal1 // access to tuple components
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
// argument labels (only first label can be omitted)
|
|
|
|
func funcWithLabels(_ param: Type, label param: Type, ...) -> Type { }
|
|
|
|
funcWithLabels(value, label: value, ...)
|
|
|
|
```
|
|
|
|
|
|
|
|
### Passing Functions as Parameters
|
|
|
|
|
|
|
|
```swift
|
|
|
|
func f(param: Type) -> Type {}
|
|
|
|
func g(f: (Type) -> Type) {} // (Type) -> Type are the passed func input and output types
|
|
|
|
```
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
### Functions Returning Functions
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
```swift
|
|
|
|
func f() -> ((Type) -> Type) {
|
|
|
|
func g(param: Type) -> type {}
|
|
|
|
|
|
|
|
return g
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## [Closure](https://docs.swift.org/swift-book/LanguageGuide/Closures.html) (`{ .. }`)
|
|
|
|
|
|
|
|
**Closures** are self-contained blocks of functionality that can be passed around and used in code.
|
|
|
|
Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
|
|
|
|
|
|
|
|
```swift
|
|
|
|
{ (parameters: Type) -> Type in
|
|
|
|
// statements
|
|
|
|
}
|
|
|
|
|
|
|
|
{ parameters in return <expression> } // type inference from context
|
|
|
|
{ $0 > $1 } // $<n> identifies the n-th argument, IN can be omitted if closure has only the body
|
|
|
|
```
|
|
|
|
|
|
|
|
## [Enums](https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html)
|
|
|
|
|
|
|
|
### Enum Definition
|
|
|
|
|
|
|
|
```swift
|
|
|
|
enum EnumName {
|
|
|
|
case key1
|
|
|
|
case key2
|
|
|
|
case ...
|
|
|
|
}
|
|
|
|
|
|
|
|
EnumName.key1 // key1
|
|
|
|
```
|
|
|
|
|
|
|
|
### Enum with Raw Values
|
|
|
|
|
|
|
|
```swift
|
|
|
|
enum EnumName: Type {
|
|
|
|
case key1 = value
|
|
|
|
case key2 = value
|
|
|
|
case ...
|
|
|
|
}
|
|
|
|
|
|
|
|
EnumName.key1.rawValue // value
|
|
|
|
|
|
|
|
enum IntegerEnum: Int {
|
|
|
|
// the value of each case is one more then the previous case
|
|
|
|
case one = 1
|
|
|
|
case two, three, four
|
|
|
|
case ...
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Matching Enumeration Values with a Switch Statement
|
|
|
|
|
|
|
|
```swift
|
|
|
|
enum Rank: Int {
|
2021-09-20 19:35:32 +02:00
|
|
|
case ace = 1, two, three, four, five, six, seven, eight, nine, ten
|
2021-01-31 11:05:37 +01:00
|
|
|
case jack, queen, king
|
|
|
|
|
|
|
|
func getValue() -> String {
|
|
|
|
switch self {
|
|
|
|
|
|
|
|
case .jack:
|
|
|
|
return "jack"
|
|
|
|
|
|
|
|
case .queen:
|
|
|
|
return "queen"
|
|
|
|
|
|
|
|
case .king:
|
|
|
|
return "king"
|
|
|
|
|
|
|
|
default:
|
|
|
|
return String(self.rawValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rank.jack.getValue() // "jack"
|
|
|
|
Rank.jack.rawValue // 11
|
|
|
|
```
|
|
|
|
|
|
|
|
## Struct (Value Type)
|
|
|
|
|
|
|
|
```swift
|
|
|
|
struct StructName {
|
|
|
|
var attribute = value // instance variable
|
|
|
|
private var _attribute: Type // backing field for property
|
|
|
|
|
|
|
|
var property: Type {
|
|
|
|
get { return _attribute }
|
|
|
|
|
|
|
|
set { _attribute = newValue } // newValue contains the passed value
|
|
|
|
// OR
|
|
|
|
set(param) { _attribute = param }
|
|
|
|
}
|
|
|
|
|
|
|
|
// constructor
|
|
|
|
init(param: Type) {
|
|
|
|
self.attribute = param // attribute valorization
|
|
|
|
}
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
// de-initializer (free memory containing obj?)
|
2021-01-31 11:05:37 +01:00
|
|
|
deinit {
|
2021-09-20 19:35:32 +02:00
|
|
|
// empty the attributes
|
2021-01-31 11:05:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// overloading
|
|
|
|
func method() -> Type { }
|
|
|
|
func method(param: Type, ...) -> Type { }
|
|
|
|
}
|
|
|
|
|
|
|
|
var structure = StructName() // struct instantiation
|
|
|
|
```
|
|
|
|
|
|
|
|
## Classes (Reference Type)
|
|
|
|
|
|
|
|
### Class Definition & Instantiation
|
|
|
|
|
|
|
|
```swift
|
|
|
|
class ClassName {
|
|
|
|
var attribute = value // instance variable
|
|
|
|
private var _attribute: Type // backing field for property
|
|
|
|
|
|
|
|
var property: Type {
|
|
|
|
get { return _attribute }
|
|
|
|
|
|
|
|
set { _attribute = newValue } // newValue contains the passed value
|
|
|
|
// OR
|
|
|
|
set(param) { _attribute = param }
|
|
|
|
}
|
|
|
|
|
|
|
|
// constructor
|
|
|
|
init(param: Type) {
|
|
|
|
self.attribute = param // attribute valorization
|
|
|
|
}
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
// de-initializer (free memory containing obj?)
|
2021-01-31 11:05:37 +01:00
|
|
|
deinit {
|
2021-09-20 19:35:32 +02:00
|
|
|
// empty the attributes
|
2021-01-31 11:05:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// overloading
|
|
|
|
func method() -> Type { }
|
|
|
|
func method(param: Type, ...) -> Type { }
|
|
|
|
}
|
|
|
|
|
|
|
|
var obj = ClassName() // obj instantiation
|
|
|
|
```
|
|
|
|
|
|
|
|
### Property Observers `willSet` & `didSet`
|
|
|
|
|
2021-09-20 19:35:32 +02:00
|
|
|
Do actions before/after modifying a property value.
|
2021-01-31 11:05:37 +01:00
|
|
|
|
2022-08-06 10:48:24 +02:00
|
|
|
> **Note**: `willSet` and `didSet` do not *set* the value of the property.
|
2021-01-31 11:05:37 +01:00
|
|
|
|
|
|
|
```swift
|
|
|
|
class ClassName {
|
|
|
|
|
|
|
|
var _attribute: Type
|
|
|
|
|
|
|
|
var property {
|
|
|
|
get { return _attribute }
|
|
|
|
set{ _attribute = newValue }
|
|
|
|
|
|
|
|
willSet {
|
|
|
|
// act before setting the property value
|
|
|
|
}
|
|
|
|
|
|
|
|
didSet {
|
2021-09-20 19:35:32 +02:00
|
|
|
// act after setting the property value
|
2021-01-31 11:05:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Inheritance
|
|
|
|
|
|
|
|
```swift
|
|
|
|
class Derived: SuperClass {
|
|
|
|
|
|
|
|
var attribute: Type
|
|
|
|
|
|
|
|
init(param1: Type, param2: Type) {
|
|
|
|
self.attribute = param1
|
|
|
|
super.init(param: param2 ) // superclass init (NEEDED)
|
|
|
|
}
|
|
|
|
|
|
|
|
// overriding
|
|
|
|
override func method() {}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Exception Handling
|
|
|
|
|
|
|
|
```swift
|
|
|
|
guard let variable = <expression>
|
|
|
|
else {
|
|
|
|
/* statements */
|
|
|
|
// throw or return to exit code branch
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
try <throwing expression>
|
|
|
|
} catch <pattern> {
|
|
|
|
// statements
|
|
|
|
}
|
|
|
|
```
|