Back to Subjects
Swift Cheatsheet
Comprehensive Swift programming guide with syntax, SwiftUI, iOS development, and best practices.
Swift Programming Cheatsheet
Basic Syntax
Hello World
import Foundation
print("Hello, World!")
// Or in a Swift playground
"Hello, World!"
Variables & Constants
// Variables (can be changed)
var name = "Swift"
var age = 10
var isAwesome = true
// Constants (cannot be changed)
let pi = 3.14159
let appName = "My App"
// Type annotations
var message: String = "Hello"
var count: Int = 42
var price: Double = 9.99
var isReady: Bool = false
// Optional variables
var optionalName: String? = nil
optionalName = "John"
// Implicitly unwrapped optionals
var forcedName: String! = "Jane"
Data Types
Basic Types
// Numbers
let integer: Int = 42
let double: Double = 3.14159
let float: Float = 2.718
let decimal: Decimal = 123.456
// Strings
let greeting = "Hello"
let multiline = """
This is a
multiline string
"""
// Characters
let letter: Character = "A"
// Booleans
let isTrue: Bool = true
let isFalse: Bool = false
// Type inference
let inferredInt = 42 // Int
let inferredDouble = 3.14 // Double
let inferredString = "Text" // String
Collections
// Arrays
var fruits = ["apple", "banana", "orange"]
var numbers: [Int] = [1, 2, 3, 4, 5]
var emptyArray: [String] = []
// Array operations
fruits.append("grape")
fruits.insert("mango", at: 0)
fruits.remove(at: 1)
let firstFruit = fruits[0]
let count = fruits.count
// Sets
var uniqueNumbers: Set<Int> = [1, 2, 3, 2, 1] // {1, 2, 3}
uniqueNumbers.insert(4)
uniqueNumbers.remove(2)
// Dictionaries
var person = ["name": "John", "age": "30"]
var scores: [String: Int] = ["Math": 95, "Science": 87]
scores["English"] = 92
scores["Math"] = nil // Remove key-value pair
Control Flow
Conditionals
// If statements
let temperature = 25
if temperature > 30 {
print("It's hot!")
} else if temperature > 20 {
print("It's warm")
} else {
print("It's cool")
}
// Guard statements
guard let name = optionalName else {
print("Name is nil")
return
}
// Switch statements
let grade = "A"
switch grade {
case "A":
print("Excellent!")
case "B", "C":
print("Good job")
case "D":
print("Need improvement")
default:
print("Invalid grade")
}
// Switch with ranges
let score = 85
switch score {
case 90...100:
print("A grade")
case 80..<90:
print("B grade")
case 70..<80:
print("C grade")
default:
print("Below C grade")
}
Loops
// For-in loops
for i in 1...5 {
print(i) // 1, 2, 3, 4, 5
}
for i in 1..<5 {
print(i) // 1, 2, 3, 4
}
// Iterating over arrays
for fruit in fruits {
print(fruit)
}
// Iterating with index
for (index, fruit) in fruits.enumerated() {
print("\(index): \(fruit)")
}
// While loops
var counter = 0
while counter < 3 {
print(counter)
counter += 1
}
// Repeat-while loops
repeat {
print("This runs at least once")
counter -= 1
} while counter > 0
Functions
Basic Functions
// Simple function
func greet() {
print("Hello!")
}
// Function with parameters
func greet(name: String) {
print("Hello, \(name)!")
}
// Function with return value
func add(a: Int, b: Int) -> Int {
return a + b
}
// Function with multiple parameters and labels
func greet(person name: String, from hometown: String) -> String {
return "Hello \(name)! Glad you could visit from \(hometown)."
}
// Call with argument labels
let greeting = greet(person: "Bill", from: "Cupertino")
// Function with default parameters
func greet(name: String = "World") {
print("Hello, \(name)!")
}
// Variadic parameters
func average(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
let avg = average(1, 2, 3, 4, 5)
Advanced Functions
// Functions as parameters
func applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
let result = applyOperation(5, 3, operation: add)
// Closures
let multiply = { (a: Int, b: Int) -> Int in
return a * b
}
// Simplified closure syntax
let divide = { a, b in a / b }
let subtract = { $0 - $1 }
// Trailing closure syntax
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
let filtered = numbers.filter { $0 > 2 }
Optionals
Working with Optionals
var optionalString: String? = "Hello"
// Optional binding (if let)
if let actualString = optionalString {
print("String is: \(actualString)")
} else {
print("String is nil")
}
// Guard let
guard let actualString = optionalString else {
print("String is nil")
return
}
// Nil coalescing operator
let greeting = optionalString ?? "Default greeting"
// Optional chaining
struct Person {
var name: String
var address: Address?
}
struct Address {
var street: String
var city: String
}
let person = Person(name: "John", address: nil)
let city = person.address?.city // Returns nil
// Force unwrapping (use carefully!)
let forcedString = optionalString! // Crashes if nil
Classes and Structures
Structures
struct Point {
var x: Double
var y: Double
// Computed property
var magnitude: Double {
return sqrt(x * x + y * y)
}
// Methods
func distance(to other: Point) -> Double {
let dx = x - other.x
let dy = y - other.y
return sqrt(dx * dx + dy * dy)
}
// Mutating methods
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var point = Point(x: 0, y: 0)
point.moveBy(x: 3, y: 4)
print(point.magnitude) // 5.0
Classes
class Vehicle {
var numberOfWheels: Int
var name: String
init(name: String, numberOfWheels: Int) {
self.name = name
self.numberOfWheels = numberOfWheels
}
func description() -> String {
return "\(name) has \(numberOfWheels) wheels"
}
}
class Car: Vehicle {
var isElectric: Bool
init(name: String, isElectric: Bool) {
self.isElectric = isElectric
super.init(name: name, numberOfWheels: 4)
}
override func description() -> String {
let type = isElectric ? "electric" : "gas-powered"
return "\(name) is a \(type) car with \(numberOfWheels) wheels"
}
}
let tesla = Car(name: "Model S", isElectric: true)
print(tesla.description())
Protocols
Basic Protocols
protocol Drawable {
func draw()
var area: Double { get }
}
protocol Named {
var name: String { get set }
}
struct Circle: Drawable, Named {
var radius: Double
var name: String
var area: Double {
return Double.pi * radius * radius
}
func draw() {
print("Drawing a circle with radius \(radius)")
}
}
// Protocol as type
let drawable: Drawable = Circle(radius: 5, name: "My Circle")
drawable.draw()
Protocol Extensions
extension Drawable {
func describe() -> String {
return "A drawable with area \(area)"
}
}
// All types conforming to Drawable now have describe() method
let circle = Circle(radius: 3, name: "Small Circle")
print(circle.describe())
Enumerations
Basic Enums
enum Direction {
case north
case south
case east
case west
}
let heading = Direction.north
// Switch with enums
switch heading {
case .north:
print("Going north")
case .south:
print("Going south")
case .east:
print("Going east")
case .west:
print("Going west")
}
Enums with Associated Values
enum Result {
case success(String)
case failure(Error)
}
enum ServerResponse {
case result(String, String)
case failure(String)
case loading
}
let response = ServerResponse.result("200", "OK")
switch response {
case .result(let code, let message):
print("Success: \(code) - \(message)")
case .failure(let error):
print("Error: \(error)")
case .loading:
print("Loading...")
}
Enums with Raw Values
enum Planet: Int {
case mercury = 1
case venus = 2
case earth = 3
case mars = 4
}
let earth = Planet.earth
print(earth.rawValue) // 3
// Initialize from raw value
if let planet = Planet(rawValue: 2) {
print("Found planet: \(planet)") // venus
}
Error Handling
Defining and Throwing Errors
enum ValidationError: Error {
case tooShort
case tooLong
case invalidCharacters
}
func validatePassword(_ password: String) throws -> Bool {
if password.count < 8 {
throw ValidationError.tooShort
}
if password.count > 128 {
throw ValidationError.tooLong
}
return true
}
// Handling errors
do {
try validatePassword("abc")
print("Password is valid")
} catch ValidationError.tooShort {
print("Password is too short")
} catch ValidationError.tooLong {
print("Password is too long")
} catch {
print("Unknown error: \(error)")
}
// Try? and try!
let result = try? validatePassword("password123") // Optional Bool
// let forced = try! validatePassword("password123") // Force unwrap
Extensions
Extending Existing Types
extension String {
var isEmail: Bool {
return self.contains("@") && self.contains(".")
}
func reversed() -> String {
return String(self.reversed())
}
mutating func reverse() {
self = String(self.reversed())
}
}
let email = "user@example.com"
print(email.isEmail) // true
print(email.reversed()) // moc.elpmaxe@resu
extension Int {
var squared: Int {
return self * self
}
func times(_ operation: () -> Void) {
for _ in 0..<self {
operation()
}
}
}
print(5.squared) // 25
3.times { print("Hello") } // Prints "Hello" 3 times
Memory Management
ARC and Strong References
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) is being deinitialized")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Weak reference to avoid retain cycle
init(unit: String) {
self.unit = unit
}
deinit {
print("Apartment \(unit) is being deinitialized")
}
}
Weak and Unowned References
// Weak references
weak var weakReference: SomeClass?
// Unowned references (use when you know the reference will never be nil)
unowned let unownedReference: SomeClass
// Closure capture lists
lazy var someClosure: () -> String = { [weak self] in
guard let self = self else { return "" }
return self.someProperty
}
SwiftUI Basics
Simple SwiftUI View
import SwiftUI
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
.font(.largeTitle)
.padding()
Button("Increment") {
count += 1
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
State Management
struct UserProfile: View {
@State private var name = ""
@State private var isEditing = false
var body: some View {
VStack {
if isEditing {
TextField("Enter name", text: $name)
.textFieldStyle(RoundedBorderTextFieldStyle())
} else {
Text("Hello, \(name.isEmpty ? "World" : name)!")
.font(.title)
}
Button(isEditing ? "Save" : "Edit") {
isEditing.toggle()
}
}
.padding()
}
}
Common Patterns
Singleton Pattern
class NetworkManager {
static let shared = NetworkManager()
private init() {
// Private initializer
}
func fetchData() {
// Network operations
}
}
// Usage
NetworkManager.shared.fetchData()
Observer Pattern with NotificationCenter
// Posting notification
NotificationCenter.default.post(name: NSNotification.Name("DataUpdated"), object: nil)
// Observing notification
NotificationCenter.default.addObserver(
self,
selector: #selector(handleDataUpdate),
name: NSNotification.Name("DataUpdated"),
object: nil
)
@objc func handleDataUpdate() {
// Handle the notification
}
Delegation Pattern
protocol DataSourceDelegate: AnyObject {
func didReceiveData(_ data: String)
}
class DataSource {
weak var delegate: DataSourceDelegate?
func fetchData() {
// Simulate data fetching
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.delegate?.didReceiveData("Sample data")
}
}
}
Useful Tips
String Interpolation
let name = "Swift"
let version = 5.5
let message = "Welcome to \(name) \(version)!"
// Custom string interpolation
extension String.StringInterpolation {
mutating func appendInterpolation<T: Numeric>(_ value: T, format: String) {
let formatted = String(format: format, value as! CVarArg)
appendLiteral(formatted)
}
}
let price = 29.99
let text = "Price: $\(price, format: "%.2f")"
Property Wrappers
@propertyWrapper
struct Capitalized {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
}
struct Person {
@Capitalized var firstName: String
@Capitalized var lastName: String
}
var person = Person()
person.firstName = "john" // Automatically becomes "John"
Result Type
enum NetworkError: Error {
case invalidURL
case noData
}
func fetchData() -> Result<String, NetworkError> {
// Simulate network call
if Bool.random() {
return .success("Data received")
} else {
return .failure(.noData)
}
}
// Usage
switch fetchData() {
case .success(let data):
print("Success: \(data)")
case .failure(let error):
print("Error: \(error)")
}
Best Practices
- Use
letinstead ofvarwhen values don't change - Prefer optionals over force unwrapping for safety
- Use guard statements for early exits
- Follow naming conventions - camelCase for variables/functions, PascalCase for types
- Use weak references to avoid retain cycles
- Leverage Swift's type system for safer code
- Use extensions to organize code and add functionality
- Prefer structs over classes when you don't need reference semantics
- Use property observers (
willSet,didSet) when needed - Write unit tests to ensure code reliability