Swift is a compiled, strongly-typed language. The compiler uses type inference to identify the type of an object, or you can explicitly use type annotation.
var favoritePeanut = "Charlie Brown" // String
var theAnswer = 42 // Int
var singleFare = 2.75 // Double (Double for "double precision" Float)
var unicodePersonInChinese = "\u{4EBA}" //Stringvar myIntArray: [Int] = [1,2,3,4]
var myHashmapMappingStringToInt: [String: Int] = ["c": 3, "b": 2]Swift can use let to declare immutable constants. Attempting to mutate a let constant will give a compile-time error
let pi = Double.pi
pi = 3 // Compile-time errorSwift conditionals do not require () syntax. If an if condition is not met, the next else if block will run. If no if or else if blocks run, an else block will run. Conditionals are not required to have else if or else blocks.
let temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."The Ternary Operator gives us a shorthand way of writing an if/else construct. Its syntax is a ? b : c and is read, "if a then b, otherwise c". In this case a would be a boolean expression, and b and c can be of any type but must be the same type.
let temperatureInFahrenheit = 60
let message = temperatureInFahrenheit <= 32 ? "cold" : "warm"
print(message) // prints "warm"Swift no longer supports C-style (for i = 0; i < 10; i++) loops. Instead, the main method of iteration is using a for in loop.
for in loops can operate over a range that's either open or closed.
for i in 0..<10 {
print(i)
}
// Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9for i in 0...10 {
print(i)
}
// Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10Swift can also iterate over any struct or class that implements the Collection protocol.
for str in ["hi", "there", "this", "is", "an", "array"] {
print(str)
}for (key, value) in ["a": 1, "b": 2, "c":3] {
print("The key is \(key) and the value is \(value)")
}Strings are Collections of Characters.
for char in "this string can be iterated over" {
print("\(char) is the character being used in the current iteration")
}struct User {
let name: String
var isLoggedIn: Bool
}
var userOne = User(name: "Adam", isLoggedIn: false)
userOne.isLoggedIn = true // Changes isLoggedIn to true
userOne.name = "Beth" //Compile error because name is a let constantclass Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}let myCounter = Counter()
// the initial counter value is 0
myCounter.increment()
// the counter's value is now 1
myCounter.increment(by: 5)
// the counter's value is now 6
myCounter.reset()
// the counter's value is now 0let radius = 5.0
let pi = Double.pi
let circleArea = pi * radius * radiusclass SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()class TwoDimensionalPoint {
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
}class ThreeDimensionalPoint: TwoDimensionalPoint {
var z: Double
init(x: Double, y: Double, z: Double) {
self.z = z
super.init(x: x, y: y)
}
}An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html
enum CompassPoint: CaseIterable {
case north
case south
case east
case west
}
let move = CompassPoint.east
switch move {
case .north:
print("moving north")
case .south:
print("moving south")
case .east:
print("moving east")
case .west:
print("moving west")
}
print("there are \(CompassPoint.allCases.count) compass points")
// iterating through an enum
for point in CompassPoint.allCases {
print(point)
}Swift have robust handling to work with data that may be nil. ? after a type indicates that it is an Optional. ! Force unwraps an optional.
var temperature: Double? = nil
if temperature != nil {
print(temperature!)
} else {
print("Thermometer has no current valid reading.")
}
// Prints "Thermometer has no current valid reading."Only optional types can be assigned to nil.
var myInt = 4
myInt = nil // Compile-time errorvar temperature: Double? = nil
if let unwrappedTemperature = temperature {
print(unwrappedTemperature)
} else {
print("Thermometer has no current valid reading.")
}
// Prints "Thermometer has no current valid readingfunc divide(_ numerator: Int, by denominator: Int) -> Int {
guard denominator != 0 else { return nil }
return numerator / denominator
}
let dividend = divide(5, by: 2) // 2
let otherDividend = divide(4, by: 0) // nilThe function divide takes in two arguments: numerator and denominator. numerator has an external parameter name of _, and denominator has an external parameter name of by. When invoking a function, we use the external parameter name. If no external parameter name is specified, it is the same as the internal argument name:
func double(value: x) -> Int {
return value * 2
}
let doubledFive = double(value: 5) //doubledFive is 10Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
https://docs.swift.org/swift-book/LanguageGuide/Closures.html
Closures in Swift are first-order types. The syntax for a closure type is as follows:
let myDoubler: (Int) -> Int = { val: Int in return val * 2 }Swift also offers a shorthand syntax using numbers prefixed by $.
let myDoubler: (Int) -> Int = { $0 * 2 }All of the following are equally valid in Swift:
// function on one line
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
// The by parameter of sorted(by:) knows its type (String, String) -> Bool
// A call to the function that defines a closure can infer the type of its arguments.
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
// If one line, "return" is inferred
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
// We can refer to arguments by numbered shorthand names so they don't need to be declared.
// This function takes two parameters. They can be found in $0 and $1
reversedNames = names.sorted(by: { $0 > $1 } )
// String overloads the > operator which works just like any function,
// Swift sees that its type, `>(_:String, _:String) -> Bool` matches what sort expects.
reversedNames = names.sorted(by: >)
// Trailing closure syntax
// When the last argument in a function is a closure, you have the option to define it outside the parentheses
reversedNames = names.sorted() { $0 > $1 }
// Trailing closure syntax omitting the parentheses
// When a closure is the only argument to a function, the parentheses can be omitted as well
reversedNames = names.sorted { $0 > $1 }