Swift

Essential Swift syntax, data structures, and common operations for iOS and macOS development.

languages
swiftiosmacosmobile

Hello World

// Print to console
print("Hello, World!")          // Basic output

// String interpolation
let name = "Swift"
print("Hello, \(name)!")        // Output: Hello, Swift!

// Multiple values
print("Values:", 42, 3.14, true) // Comma-separated

Variables

// Immutable constants (preferred)
let name = "Alice"              // Type inference
let age: Int = 30               // Explicit type
let pi = 3.14159                // Double by default

// Mutable variables
var score = 0                   // Can be changed
var message: String = "Hello"   // Explicit type

// Multiple declarations
let x = 5, y = 10, z = 15

Data Types

// Basic types
let integer: Int = 42           // Integer
let decimal: Double = 3.14      // Double precision
let float: Float = 2.5          // Single precision
let text: String = "Swift"      // String
let flag: Bool = true           // Boolean
let character: Character = "A"  // Single character

// Type conversion
let intValue = Int(3.14)        // 3
let stringValue = String(42)    // "42"
let doubleValue = Double("3.14")// Optional(3.14)

Optionals

// Optional declaration
var optionalString: String? = "Hello"
var optionalInt: Int? = nil     // Explicitly nil

// Unwrapping optionals
if let unwrapped = optionalString {
    print(unwrapped)            // Safe unwrapping
}

// Nil coalescing
let result = optionalString ?? "Default"  // Use default if nil

// Optional chaining
let length = optionalString?.count        // Returns optional

// Force unwrapping (use with caution)
let forced = optionalString!              // Crashes if nil

// Guard statement
func process(value: String?) {
    guard let value = value else {
        return                  // Early exit if nil
    }
    print(value)
}

Collections

// Arrays (ordered)
var fruits = ["apple", "banana", "cherry"]
fruits.append("date")           // Add element
fruits[0]                       // Access by index
fruits.count                    // Number of elements
fruits.isEmpty                  // Check if empty

// Array operations
let doubled = fruits.map { $0.uppercased() }
let filtered = fruits.filter { $0.hasPrefix("a") }
let first = fruits.first        // Optional first element

// Dictionaries (key-value pairs)
var person = [
    "name": "Alice",
    "city": "NYC"
]
person["name"]                  // Returns Optional("Alice")
person["email"] = "a@example.com"  // Add/update
person["city"] = nil            // Remove key

// Sets (unique, unordered)
var numbers: Set = [1, 2, 3, 3] // Duplicates removed
numbers.insert(4)               // Add element
numbers.contains(2)             // true

Control Flow

// If-else
let temperature = 72
if temperature > 80 {
    print("Hot")
} else if temperature > 60 {
    print("Nice")
} else {
    print("Cold")
}

// Switch (exhaustive, no fallthrough)
let grade = "B"
switch grade {
case "A":
    print("Excellent")
case "B", "C":                  // Multiple cases
    print("Good")
case "D"...:                    // Range matching
    print("Needs improvement")
default:
    print("Invalid")
}

// For loops
for i in 1...5 {                // Closed range (1 to 5)
    print(i)
}

for i in 1..<5 {                // Half-open range (1 to 4)
    print(i)
}

for fruit in fruits {           // Iterate collection
    print(fruit)
}

// While loops
var count = 0
while count < 5 {
    count += 1
}

repeat {                        // Do-while equivalent
    count -= 1
} while count > 0

Functions

// Basic function
func greet(name: String) -> String {
    return "Hello, \(name)!"    // String interpolation
}

// Multiple parameters
func add(_ a: Int, to b: Int) -> Int {
    return a + b
}
add(5, to: 3)                   // Argument labels

// Default parameters
func greet(name: String, greeting: String = "Hello") -> String {
    return "\(greeting), \(name)!"
}

// Multiple return values (tuple)
func minMax(numbers: [Int]) -> (min: Int, max: Int)? {
    guard let first = numbers.first else {
        return nil
    }
    var min = first, max = first
    for number in numbers {
        if number < min { min = number }
        if number > max { max = number }
    }
    return (min, max)
}

// Inout parameters (pass by reference)
func increment(_ value: inout Int) {
    value += 1
}
var counter = 5
increment(&counter)             // counter is now 6

Closures

// Closure expression
let multiply = { (a: Int, b: Int) -> Int in
    return a * b
}
multiply(3, 4)                  // 12

// Trailing closure syntax
let numbers = [1, 2, 3, 4, 5]
let squared = numbers.map { $0 * $0 }  // [1, 4, 9, 16, 25]

// Capturing values
func makeIncrementer(increment: Int) -> () -> Int {
    var total = 0
    return {
        total += increment
        return total
    }
}
let incrementByTwo = makeIncrementer(increment: 2)
incrementByTwo()                // 2
incrementByTwo()                // 4

Structs and Classes

// Struct (value type, preferred)
struct Point {
    var x: Int
    var y: Int
    
    // Method
    mutating func moveBy(x deltaX: Int, y deltaY: Int) {
        x += deltaX
        y += deltaY
    }
}

var point = Point(x: 0, y: 0)   // Memberwise initializer
point.moveBy(x: 5, y: 10)

// Class (reference type)
class Person {
    var name: String
    var age: Int
    
    // Initializer
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    // Method
    func introduce() -> String {
        return "I'm \(name), \(age) years old"
    }
}

let person = Person(name: "Alice", age: 30)
person.introduce()

// Inheritance
class Student: Person {
    var studentId: String
    
    init(name: String, age: Int, studentId: String) {
        self.studentId = studentId
        super.init(name: name, age: age)
    }
    
    override func introduce() -> String {
        return "\(super.introduce()), ID: \(studentId)"
    }
}

Error Handling

// Define error enum
enum FileError: Error {
    case fileNotFound
    case insufficientPermissions
    case corrupted
}

// Throwing function
func readFile(path: String) throws -> String {
    if path.isEmpty {
        throw FileError.fileNotFound
    }
    return "File contents"
}

// Handling errors with do-catch
do {
    let contents = try readFile(path: "/path/to/file")
    print(contents)
} catch FileError.fileNotFound {
    print("File not found")
} catch {
    print("Unknown error: \(error)")
}

// Optional try (converts error to nil)
let contents = try? readFile(path: "/path")  // Returns optional

// Force try (crashes on error, use with caution)
let data = try! readFile(path: "/guaranteed/path")

String Operations

let text = "Hello, Swift!"

// Properties
text.count                      // 13
text.isEmpty                    // false
text.uppercased()               // "HELLO, SWIFT!"
text.lowercased()               // "hello, swift!"

// Checking content
text.hasPrefix("Hello")         // true
text.hasSuffix("!")             // true
text.contains("Swift")          // true

// Splitting and joining
let words = text.split(separator: " ")  // ["Hello,", "Swift!"]
let joined = words.joined(separator: "-")

// Substring
let index = text.index(text.startIndex, offsetBy: 5)
let substring = text[..<index]  // "Hello"

// String interpolation
let name = "Alice"
let age = 30
let message = "Name: \(name), Age: \(age)"

Array Operations

var numbers = [1, 2, 3, 4, 5]

// Transformation
let doubled = numbers.map { $0 * 2 }           // [2, 4, 6, 8, 10]
let strings = numbers.map { String($0) }       // ["1", "2", "3", "4", "5"]

// Filtering
let evens = numbers.filter { $0 % 2 == 0 }     // [2, 4]
let odds = numbers.filter { $0 % 2 != 0 }      // [1, 3, 5]

// Reducing
let sum = numbers.reduce(0, +)                 // 15
let product = numbers.reduce(1, *)             // 120

// Sorting
let sorted = numbers.sorted()                  // Ascending
let reversed = numbers.sorted { $0 > $1 }      // Descending

// Finding
let firstEven = numbers.first { $0 % 2 == 0 }  // Optional(2)
let containsFive = numbers.contains(5)         // true

// Combining
let combined = numbers.compactMap { $0 % 2 == 0 ? $0 : nil }  // [2, 4]

Enumerations

// Basic enum
enum Direction {
    case north
    case south
    case east
    case west
}

var heading = Direction.north
heading = .south                // Short syntax

// Enum with raw values
enum Planet: Int {
    case mercury = 1
    case venus = 2
    case earth = 3
}

let earth = Planet.earth
earth.rawValue                  // 3

// Enum with associated values
enum Result {
    case success(String)
    case failure(Error)
}

let result = Result.success("Data loaded")

switch result {
case .success(let message):
    print(message)
case .failure(let error):
    print("Error: \(error)")
}

Property Observers

struct BankAccount {
    var balance: Double = 0 {
        willSet {
            print("About to set balance to \(newValue)")
        }
        didSet {
            if balance < 0 {
                balance = oldValue  // Revert if negative
            }
        }
    }
}

var account = BankAccount()
account.balance = 100           // Triggers willSet and didSet

Extensions

// Extend existing types
extension Int {
    var squared: Int {
        return self * self
    }
    
    func times(_ action: () -> Void) {
        for _ in 0..<self {
            action()
        }
    }
}

5.squared                       // 25
3.times {
    print("Hello")              // Prints "Hello" 3 times
}

// Extend custom types
extension Point {
    func distance(to other: Point) -> Double {
        let dx = Double(x - other.x)
        let dy = Double(y - other.y)
        return sqrt(dx * dx + dy * dy)
    }
}