Basics
See
A Swift Tour
https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1
Getting Started
Size, Stride, Alignment
Swift And C: Everything You Need to Know on Types, Pointers and more
https://www.uraimo.com/2016/04/07/swift-and-c-everything-you-need-to-know/
swift --version
swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: x86_64-apple-macosx13.0
To start the REPL commandline:
swift repl
./code/1-hello.swift
// swiftc ./1-hello.swift
print("Hello, world!")
// Note:
// 1. It is not println but it still prints a new line
// 2. There is no semicolon
// 3. There is no main(), like Python
swiftc ./1-hello.swift
It will generate an executable ./1-hello
.
otool -L ./1-hello
./1-hello:
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
/usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 5.7.1)
ls -lh 1-hello
-rwxr-xr-x 1 fangjun staff 33K Jan 21 11:55 1-hello
./code/2-variables.swift
var myVariable = 42
myVariable = 50
let myConstant = 43
print("myVariable is \(myVariable)")
print("myConstant is \(myConstant)")
let implicitInteger = 1
let implicitDouble = 1.0
let explicitDouble: Double = 1
let label = "The width is "
let width = 100
var widthLabel = label + String(width)
widthLabel = "\(label)\(width)"
print(widthLabel)
// """
let s = """
abc
def
"""
// Note: there are leading spaces before the ending """
print(s)
./code/3-array-dict.swift
var fruits = ["strawberries", "limes", "apples"]
fruits[1] = "grapes"
print(fruits) // ["strawberries", "grapes", "apples"]
fruits.append("blueberries")
var occupations = [
"Tom": "Captain",
"Jerry": "Mechanic",
]
print(occupations) // ["Tom": "Captain", "Jerry": "Mechanic"]
occupations["Tom"] = "Teacher"
let emptyArray: [String] = []
let emptyDict: [String: Float] = [:]
./code/4-if.swift
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
// 11
print(teamScore)
var optionalString: String? = "Hello"
// false
print(optionalString == nil)
var optionalName: String? = "Tom"
var greeting = "Hello!"
// if optionalName is nil, then the condition is false
// if optionalName is not nil, then the condition is true and optionalName is unwrapped and assigned to name
if let name = optionalName {
greeting = "Hello,\(name)"
}
// Hello,Tom
print(greeting)
let nickname: String? = nil
let fullName: String = "Tom Green"
// Hi, Tom Green
let informalGreeting = "Hi, \(nickname ?? fullName)"
print(informalGreeting)
if let nickname {
print("Hey, \(nickname)")
}
./code/5-switch.swift
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("celery")
case "cucumber", "watercress":
print("cucumber or watercress")
case let x where x.hasSuffix("pepper"):
print("x")
default:
print("Everything tastes good in soup.")
}
// 1. no need to use break
// 2. default is mandatory so that it is exhaustive
./code/6-for.swift
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (_, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest) // 25
var total = 0
for i in 0..<4 {
total += i
}
print(total) // 6
total = 0
for i in 0...4 {
total += i
}
print(total) // 10
./code/7-while.swift
var n = 2
while n < 100 {
n *= 2;
}
print(n) // 128
var m = 2
repeat {
m *= 2;
} while (m < 100)
print(m) // 128
./code/8-func.swift
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)"
}
print(greet(person: "Bob", day: "Tuesday"))
// print(greet("Bob", day: "Tuesday")) // error: missing argument label 'person:' in call
func greet2(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)"
}
// print(greet2(person: "Bob", day: "Tuesday")) // error: incorrect argument labels in call (have 'person:day:', expected '_:on:')
print(greet2("Bob", on: "Tuesday"))
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[1]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum) // 120
print(statistics.2) // 120
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
print(returnFifteen()) // 15
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return number + 1
}
return addOne
}
var increment = makeIncrementer()
print(increment(7)) // 8
func hasAnyElement(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
print(hasAnyElement(list: numbers, condition: lessThanTen)) // true
// the closure has to be put in {}
print(hasAnyElement(list: numbers, condition: {(number: Int) -> Bool in number < 1})) // false
// we can omit the input argument type and return type
print(hasAnyElement(list: numbers, condition: {number in number < 1})) // false
print(numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})) // [60, 57, 21, 36]
let mappedNumber = numbers.map({number in 3 * number})
print(mappedNumber) // [60, 57, 21, 36]
var sortedNumbers = numbers.sorted {$0 > $1}
print(sortedNumbers) // [20, 19, 12, 7]
sortedNumbers = numbers.sorted {$0 < $1} // also ok
print(sortedNumbers) // [7, 12, 19, 20]
./code/9-class.swift
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
var shape = Shape()
print(shape.numberOfSides) // 0
shape.numberOfSides = 4
print(shape.numberOfSides) // 4
var simpleDescription = shape.simpleDescription()
print(simpleDescription) // A shape with 4 sides
// with constructor
class NamedShape {
var numberOfSides = 0
var name: String
init(name: String, numberOfSides: Int) {
self.name = name
self.numberOfSides = numberOfSides
}
func simpleDescription() -> String {
return "\(name): A shape with \(numberOfSides) sides"
}
}
var namedShape = NamedShape(name: "Hello", numberOfSides: 10)
print(namedShape.simpleDescription())
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name, numberOfSides: 4)
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with side length \(sideLength)"
}
}
var square = Square(sideLength: 10, name: "MySquare")
print(square.simpleDescription()) // A square with side length 10.0
print(square.area()) // 100.0
// property getter/setter
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name, numberOfSides: 3)
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
// note: the new value has the implicit name newValue
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with side of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 10, name: "MyTriangle")
print(triangle.perimeter) // 30.0
triangle.perimeter = 15
print(triangle.perimeter) // 15.0
print(triangle.sideLength) // 5.0
./code/10-enum.swift
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
print(ace) // ace
print(aceRawValue) // 1
let two = Rank(rawValue: 2)
print(two ?? "zwei") // two
./code/11-memory-layout.swift
assert(MemoryLayout<Bool>.size == 1)
assert(MemoryLayout<Bool>.stride == 1)
assert(MemoryLayout<Bool>.alignment == 1)
assert(MemoryLayout<Int>.size == 8)
assert(MemoryLayout<Int>.stride == 8)
assert(MemoryLayout<Int>.alignment == 8)
assert(MemoryLayout<Int32>.size == 4)
assert(MemoryLayout<Int32>.stride == 4)
assert(MemoryLayout<Int32>.alignment == 4)
// Like C/C++
struct Example {
let foo: Int // 8
let bar: Bool // 1
}
assert(MemoryLayout<Example>.size == 9)
assert(MemoryLayout<Example>.stride == 16)
assert(MemoryLayout<Example>.alignment == 8)
let ex = Example(foo: 10, bar: true)
assert(MemoryLayout.size(ofValue: ex) == 9)
assert(MemoryLayout.stride(ofValue: ex) == 16)
assert(MemoryLayout.alignment(ofValue: ex) == 8)
struct Example2 {
let bar: Bool // 1
let foo: Int // 8
}
assert(MemoryLayout<Example2>.size == 16)
assert(MemoryLayout<Example2>.stride == 16)
assert(MemoryLayout<Example2>.alignment == 8)
./code/12-weak-reference.swift
class Author {
let name: String
// weak reference is required
weak var post: Post?
init(name: String) {self.name = name}
deinit {print("Author deinit")}
}
class Post {
let title: String
var author: Author?
init(title: String) {self.title = title}
deinit {print("Post deinit")}
}
var author: Author? = Author(name: "John Snow")
var post: Post? = Post(title: "foo bar")
post?.author = author
author?.post = post
print(author?.post) // Optional(main.Post)
post = nil // Post deinit
print(author?.post) // nil
author = nil // Author deinit
./code/13-pointers.swift
// Unsafe[Mutable][Raw][Buffer]Pointer[Type]
//
// Mutable: means you can change the value
// Raw: means it points to a blob of bytes
// Buffer: means it works like a collection
// Type: means generic typed pointers
//
// UnsafePointer<T>
// UnsafeMutablePointer<T>
//
// UnsafeRawPointer
// UnsafeMutableRawPointer
//
// UnsafeRawBufferPointer
// UnsafeMutableRawBufferPointer
//
// UnsafeBufferPointer<T>
// UnsafeMutableBufferPointer<T>
let count = 2
let stride = MemoryLayout<Int>.stride
let alignment = MemoryLayout<Int>.alignment
let byteCount = count * stride
let pointer = UnsafeMutableRawPointer.allocate(byteCount: byteCount, alignment: alignment)
defer {
pointer.deallocate()
}
pointer.storeBytes(of: 30, as: Int.self)
pointer.advanced(by: stride).storeBytes(of: 3, as: Int.self)
assert(pointer.load(as: Int.self) == 30)
assert(pointer.load(fromByteOffset: stride, as: Int.self) == 3)
assert(pointer.advanced(by: stride).load(as: Int.self) == 3)
let bufferPointer = UnsafeRawBufferPointer(start: pointer, count: byteCount)
for (index, byte) in bufferPointer.enumerated() {
print("byte \(index) -> \(byte)")
}
/*
byte 0 -> 30
byte 1 -> 0
byte 2 -> 0
byte 3 -> 0
byte 4 -> 0
byte 5 -> 0
byte 6 -> 0
byte 7 -> 0
byte 8 -> 3
byte 9 -> 0
byte 10 -> 0
byte 11 -> 0
byte 12 -> 0
byte 13 -> 0
byte 14 -> 0
byte 15 -> 0
*/
./code/14-typed-pointers.swift
let count = 2
let stride = MemoryLayout<Int>.stride
let pointer = UnsafeMutablePointer<Int>.allocate(capacity: count)
pointer.initialize(repeating: 0, count: count)
defer {
pointer.deinitialize(count: count)
pointer.deallocate()
}
pointer.pointee = 42
pointer.advanced(by: 1).pointee = 6
let bufferPointer = UnsafeBufferPointer(start: pointer, count: count)
for (index, value) in bufferPointer.enumerated() {
print("value \(index) -> \(value)")
}
/*
value 0 -> 42
value 1 -> 6
*/