Swift Interview Questions with Answers
Most Asked Swift Interview Questions for Software Engineer Roles
Introduction
Swift is a powerful and intuitive programming language developed by Apple for building apps for iOS, macOS, watchOS, and tvOS. Designed to be safe, fast, and expressive, Swift combines the performance of compiled languages with the simplicity and interactivity of modern scripting languages. This comprehensive guide presents 100+ carefully curated Swift interview questions and answers, covering everything from the fundamentals to advanced topics. You'll master variables, data types, optionals, control flow, functions, closures, structs, classes, protocols, generics, error handling, concurrency (async/await, actors, DispatchQueue), extensions, property wrappers, and real-world iOS development patterns. Whether you're preparing for an iOS developer role, a macOS engineer position, or a Swift backend job (Vapor), this question bank will solidify your understanding and give you the confidence to ace your interview. Start practicing now and become a Swift expert.
Why Swift?
- Modern, safe, and fast – designed for Apple's ecosystem and beyond
- Strong type system with optionals for null safety
- Excellent tooling with Xcode and Swift Package Manager
- Used for iOS, macOS, watchOS, tvOS, and server-side (Vapor)
- Growing community and high demand in the job market
- Open source with continuous innovation from Apple and the community
Most Asked Swift Interview Questions
Swift is a powerful and intuitive programming language developed by Apple for iOS, macOS, watchOS, and tvOS app development.
- Safe: Designed for safety with optionals and type safety
- Fast: Compiled to native code for high performance
- Expressive: Clean syntax with modern features
- Interoperable: Works with Objective-C and C
- Open source: Available for multiple platforms
// Hello World in Swift
import Foundation
print("Hello, World!")
// Using function
func greet() {
print("Hello, World!")
}
greet()Variables in Swift are declared with var (mutable) and let (immutable). Type inference is supported.
- let: Immutable constant
- var: Mutable variable
- Type inference: Types can be omitted
- Explicit types:
let name: String = "Alice" - Optionals:
Type?for nullable values
// Variables in Swift
// Immutable variable (let - constant)
let immutableVar = "World"
// Mutable variable (var)
var mutableVar = "Hello"
mutableVar = "Swift"
// Type inference
var inferred = 42
// Explicit type annotation
var explicit: Int = 10
// Constants
let pi: Double = 3.14159
// Display
print(immutableVar)
print(mutableVar)
print(inferred)
print(explicit)
print(pi)
// Optional variable (can be nil)
var optionalVar: String? = "Optional"
// Multiple declarations
var (a, b) = (1, 2)Swift has a rich type system with both primitive and complex types, including optionals for null safety.
- Integers: Int, UInt, Int8, Int16, Int32, Int64
- Floating point: Float, Double
- Boolean: Bool
- Character: Character
- String: String
- Array: [Type]
- Dictionary: [Key: Value]
- Tuple: (Type1, Type2)
- Optional: Type?
// Data Types in Swift
// Integer types
let intNum: Int = 10
let unsigned: UInt = 100
let int8: Int8 = 127
let int64: Int64 = 1000000
// Floating point
let floatNum: Float = 3.14
let doubleNum: Double = 3.14159
// Boolean
let isActive: Bool = true
let isInactive: Bool = false
// Character
let charVal: Character = "A"
// String
let strVal: String = "Hello Swift"
// Array
let arr: [Int] = [1, 2, 3, 4, 5]
// Tuple
let tuple: (Int, Double, String) = (10, 3.14, "hello")
// Dictionary
let dict: [String: Int] = ["one": 1, "two": 2]
// Optional
var optional: Int? = nil
// Type checking
print(type(of: intNum))Functions in Swift are defined with the func keyword. They support parameters, return values, and closures.
- Basic:
func name(parameters) -> ReturnType { } - Default parameters:
func greet(name: String = "Guest") - Multiple returns:
func divide() -> (Int, Int) - Variadic parameters:
func sum(_ numbers: Int...) - Closures:
{ (params) -> ReturnType in }
// Functions in Swift
// Basic function
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
// Function with multiple return values (tuple)
func divide(_ a: Int, _ b: Int) -> (quotient: Int, remainder: Int) {
return (a / b, a % b)
}
// Function with default parameters
func greet(_ name: String = "Guest") -> String {
return "Hello, \(name)!"
}
// Function with variadic parameters
func sum(_ numbers: Int...) -> Int {
return numbers.reduce(0, +)
}
// Higher-order function
func operate(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
// Closure (lambda)
let multiply = { (a: Int, b: Int) -> Int in
return a * b
}
// Usage
print(add(5, 3))
let result = divide(10, 3)
print("Quotient: \(result.quotient), Remainder: \(result.remainder)")
print(greet("Alice"))
print(sum(1, 2, 3, 4, 5))
print(operate(6, 7, operation: multiply))Arrays are ordered collections of elements of the same type. They can be mutable or immutable.
- Creation:
let numbers = [1, 2, 3] - Access:
numbers[0] - Modification:
numbers.append(4) - Methods:
map,filter,reduce - Type safety: Homogeneous types
// Arrays in Swift
// Array creation
var numbers: [Int] = [1, 2, 3, 4, 5]
var strings: [String] = ["Apple", "Banana", "Orange"]
var mixed: [Any] = [1, "Hello", 3.14]
// Access and modify
print(numbers[2]) // Access element
numbers[2] = 10 // Modify element
// Array operations
print(numbers.count)
numbers.append(6) // Add element
numbers.removeLast() // Remove last element
// Iteration
for num in numbers {
print(num)
}
// Array methods
let doubled = numbers.map { $0 * 2 }
let filtered = numbers.filter { $0 > 2 }
let sum = numbers.reduce(0, +)
// Display
print(doubled)
print(filtered)
print(sum)
// Array with type annotation
var emptyArray: [Int] = []
var anotherEmpty = [Int]()Swift collections include Array, Set, and Dictionary, each with immutable and mutable variants.
- Array: Ordered collection with duplicates
- Set: Unordered collection without duplicates
- Dictionary: Key-value pairs
- Immutability:
letfor immutable - Operations:
filter,map,reduce
// Collections in Swift
// Array (ordered, allows duplicates)
let immutableArray = [1, 2, 3, 4, 5]
var mutableArray = [1, 2, 3]
mutableArray.append(4)
mutableArray.remove(at: 1)
// Set (unordered, unique values)
let immutableSet: Set = [1, 2, 3]
var mutableSet: Set = [1, 2, 3]
mutableSet.insert(4)
mutableSet.remove(2)
// Dictionary (key-value pairs)
let immutableDict: [String: String] = ["key1": "value1", "key2": "value2"]
var mutableDict: [String: String] = ["key1": "value1"]
mutableDict["key2"] = "value2"
mutableDict.removeValue(forKey: "key1")
// Collection operations
let numbers = [1, 2, 3, 4, 5, 6]
let evens = numbers.filter { $0 % 2 == 0 }
let doubled = numbers.map { $0 * 2 }
let sum = numbers.reduce(0, +)
print(evens)
print(doubled)
print(sum)Structs are value types that encapsulate data and behavior. They are the preferred data model in Swift.
- Definition:
struct Person { var name: String } - Value type: Copied when assigned
- Methods:
func greet() - Mutating:
mutating funcfor modifications - Memberwise initializer: Automatic initializer
// Structs (Data Classes) in Swift
struct Person {
var name: String
var age: Int
var city: String
// Initializer (provided automatically)
// Memberwise initializer: Person(name:age:city:)
// Method
func greet() -> String {
return "Hello, my name is \(name)"
}
// Mutating method
mutating func incrementAge() {
age += 1
}
}
// Struct with default values
struct User {
var name: String
var age: Int = 0
var city: String = "Unknown"
}
// Usage
var person1 = Person(name: "Alice", age: 25, city: "NYC")
let person2 = person1 // Copy (structs are value types)
// Update using struct update syntax
var person3 = person1
person3.age = 26
print(person1.name)
print(person1.age)
print(person1.city)
print(person1.greet())
// User with default
let user = User(name: "Bob")
print(user.city)Enums define a set of related values. They can have associated values and raw values.
- Definition:
enum Status { case active, inactive } - Associated values:
case success(String) - Raw values:
enum Status: Int { case active = 1 } - Methods: Can have computed properties and methods
- Pattern matching:
switchstatements
// Enums (Sealed Classes) in Swift
enum Result<T, E: Error> {
case success(T)
case failure(E)
}
enum Shape {
case circle(radius: Double)
case rectangle(width: Double, height: Double)
case point
}
extension Shape {
func area() -> Double {
switch self {
case .circle(let radius):
return Double.pi * radius * radius
case .rectangle(let width, let height):
return width * height
case .point:
return 0
}
}
}
// Enum with associated values
enum Payment {
case cash(amount: Double)
case creditCard(number: String, expiry: String)
case paypal(email: String)
}
func handlePayment(_ payment: Payment) -> String {
switch payment {
case .cash(let amount):
return "Cash amount: $\(amount)"
case .creditCard(let number, let expiry):
return "Card: \(number), Expiry: \(expiry)"
case .paypal(let email):
return "PayPal: \(email)"
}
}
// Enum with raw values
enum Status: Int {
case success = 200
case error = 500
case loading = 100
}
enum Color: String {
case red = "RED"
case green = "GREEN"
case blue = "BLUE"
}
// Usage
let result = Result.success("Data loaded")
let shape = Shape.circle(radius: 5.0)
let payment = Payment.creditCard(number: "1234-5678", expiry: "12/25")
print(shape.area())
print(handlePayment(payment))
print(Status.success.rawValue)
print(Color.red.rawValue)Swift uses optionals for null safety, requiring explicit handling of nil values.
- Optionals:
Type? - Optional binding:
if let - Guard statements:
guard let - Nil coalescing:
?? - Optional chaining:
?
// Null Safety in Swift (Optionals)
func main() {
// Optional types
var nullableString: String? = "Hello"
var nullString: String? = nil
// Safe access with optional binding
if let str = nullableString {
print("String is: \(str)")
print("Length: \(str.count)")
}
// Guard statement
guard let str = nullableString else {
print("String is nil")
return
}
print("Guard: \(str)")
// Nil-coalescing operator (Elvis operator)
let value = nullString ?? "default"
print("Value: \(value)")
// Optional chaining
let length = nullableString?.count ?? 0
print("Length: \(length)")
// Force unwrap (use carefully!)
let forced = nullableString!
print("Forced: \(forced)")
// Map and flatMap
let upper = nullableString.map { $0.uppercased() }
print("Upper: \(upper ?? "nil")")
// Optional pattern matching
if case .some(let str) = nullableString {
print("Pattern matched: \(str)")
}
}
main()Swift provides if-else, switch, for-in, while, and repeat-while loops for control flow.
- If-else:
if condition { } else { } - Switch:
switch value { case pattern: } - For-in:
for item in collection { } - While:
while condition { } - Repeat-while:
repeat { } while condition
// Control Flow in Swift
// If-else
let age = 25
let status = age < 18 ? "Minor" : "Adult"
print(status)
// If-else-if
let grade = "A"
var result: String
if grade == "A" {
result = "Excellent"
} else if grade == "B" {
result = "Good"
} else if grade == "C" {
result = "Fair"
} else {
result = "Needs Improvement"
}
print(result)
// Switch statement
let score = 85
switch score {
case 90...100:
print("A")
case 80..<90:
print("B")
case 70..<80:
print("C")
default:
print("F")
}
// For-in loop
for i in 0..<5 {
print(i)
}
// For-in with step
for i in stride(from: 1, through: 10, by: 2) {
print(i)
}
// For-in descending
for i in (0..<10).reversed() {
print(i)
}
// While loop
var i = 0
while i < 5 {
print(i)
i += 1
}
// Repeat-while (do-while)
i = 0
repeat {
print(i)
i -= 1
} while i > 0
// For-in with where clause
for i in 1...10 where i % 2 == 0 {
print("Even: \(i)")
}Swift supports classes with single inheritance, protocols for interfaces, and method overriding.
- Class definition:
class Animal - Inheritance:
class Dog: Animal - Override:
override func - Protocols:
protocol Flyable - Reference types: Shared instance
// Classes and Inheritance in Swift
// Base class
class Animal {
var name: String
init(name: String) {
self.name = name
}
func makeSound() -> String {
return "Animal sound"
}
}
// Derived class
class Dog: Animal {
var breed: String
init(name: String, breed: String) {
self.breed = breed
super.init(name: name)
}
override func makeSound() -> String {
return "Woof!"
}
}
// Abstract class (using protocol)
protocol Vehicle {
func start() -> String
}
extension Vehicle {
func stop() -> String {
return "Stopped"
}
}
// Car implementing protocol
class Car: Vehicle {
func start() -> String {
return "Car started"
}
}
// Multiple protocols
protocol Flyable {
func fly() -> String
}
protocol Swimmable {
func swim() -> String
}
class Duck: Flyable, Swimmable {
func fly() -> String {
return "Flying"
}
func swim() -> String {
return "Swimming"
}
}
// Usage
let dog = Dog(name: "Rex", breed: "German Shepherd")
print(dog.makeSound())
print(dog.name)
print(dog.breed)
let duck = Duck()
print(duck.fly())
print(duck.swim())Properties in Swift include stored, computed, lazy, and observed properties with property wrappers.
- Stored:
var name: String - Computed:
var fullName: String { return name } - Lazy:
lazy var data = { }() - Observers:
didSet,willSet - Property wrappers:
@State,@Binding
// Properties in Swift
class Person {
// Stored properties
var name: String
var age: Int
// Computed property
var fullName: String {
return "\(name) (Age: \(age))"
}
// Lazy property
lazy var expensiveData: String = {
print("Computing expensive data...")
return "Expensive Result"
}()
// Property observer
var email: String {
didSet {
print("Email changed from \(oldValue) to \(email)")
}
}
// Read-only computed property
var isAdult: Bool {
return age >= 18
}
// Init with validation
init(name: String, age: Int, email: String) {
self.name = name
self.age = age
self.email = email
}
// Setter with validation
func setAge(_ newAge: Int) {
if newAge >= 0 {
age = newAge
}
}
}
// Struct with property wrapper
@propertyWrapper
struct Trimmed {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
}
struct User {
@Trimmed var name: String
}
// Usage
let person = Person(name: "Alice", age: 25, email: "alice@example.com")
print(person.fullName)
print(person.expensiveData)
print(person.isAdult)
var user = User(name: " Alice ")
print(user.name) // "Alice" (trimmed)Class methods are defined with static or class keywords. Static methods cannot be overridden.
- Static:
static func method() - Class:
class func method() - Singleton pattern:
static let shared = Class() - Factory methods: Create instances
- Type properties:
static var
// Class Methods and Static Methods
class MyClass {
// Class variable (static)
static var counter = 0
static let tag = "MyClass"
// Static method
static func classMethod() {
print("Class method called, counter: \(counter)")
}
// Factory method
static func create() -> MyClass {
counter += 1
return MyClass()
}
// Instance method
func instanceMethod() {
print("Instance method called")
}
}
// Class with singleton
class Singleton {
static let shared = Singleton()
private init() {} // Private initializer
var data: [String] = []
func addData(_ item: String) {
data.append(item)
}
}
// Usage
print(MyClass.tag)
let obj1 = MyClass.create()
let obj2 = MyClass.create()
MyClass.classMethod()
let singleton1 = Singleton.shared
let singleton2 = Singleton.shared
singleton1.addData("Hello")
print(singleton2.data) // ["Hello"]Swift uses throws, do-catch, try?, and try! for error handling.
- Throws:
func method() throws - Do-catch:
do { try } catch { } - Try?: Returns optional
try? - Try!: Force unwrap
try! - Defer: Cleanup code
// Exception Handling in Swift
// Custom error
enum AgeError: Error {
case invalidAge(age: Int)
case negativeAge
}
// Function that throws
func validateAge(_ age: Int) throws {
if age < 0 {
throw AgeError.negativeAge
}
if age > 150 {
throw AgeError.invalidAge(age: age)
}
}
// Function with try
func divide(_ a: Int, _ b: Int) throws -> Int {
guard b != 0 else {
throw NSError(domain: "DivideError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Division by zero"])
}
return a / b
}
// Usage
func main() {
// do-catch
do {
try validateAge(25)
print("Age is valid")
} catch AgeError.negativeAge {
print("Age cannot be negative")
} catch AgeError.invalidAge(let age) {
print("Invalid age: \(age)")
} catch {
print("Unknown error: \(error)")
}
// try? (returns nil on error)
let result = try? divide(10, 2)
print("Result: \(result ?? 0)")
// try! (force, crashes on error)
// let forced = try! divide(10, 2)
// defer (finally equivalent)
func readFile() {
defer {
print("Closing resources...")
}
print("Reading file...")
}
readFile()
// Result type
let result2 = Result { try divide(10, 2) }
switch result2 {
case .success(let value):
print("Success: \(value)")
case .failure(let error):
print("Error: \(error)")
}
}
main()Closures are self-contained blocks of functionality that can be passed around and used in code.
- Syntax:
{ (params) -> ReturnType in } - Shorthand:
{ $0 + $1 } - Trailing closures:
func() { } - Capturing values: Captures variables
- Escaping:
@escapingfor stored closures
// Closures in Swift
// Basic closure
let square = { (x: Int) -> Int in
return x * x
}
// Closure with multiple parameters
let add = { (a: Int, b: Int) -> Int in
return a + b
}
// Closure with multiple lines
let complexOperation = { (x: Int) -> Int in
let y = x * 2
return y + 10
}
// Higher-order function
func operate(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
// Closure capturing environment
func makeMultiplier(_ factor: Int) -> (Int) -> Int {
return { x in
return x * factor
}
}
// Trailing closure
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
let filtered = numbers.filter { $0 > 2 }
// Closure with shorthand argument names
let sum = numbers.reduce(0) { $0 + $1 }
// Escaping closure
var completionHandlers: [() -> Void] = []
func addCompletionHandler(handler: @escaping () -> Void) {
completionHandlers.append(handler)
}
// Usage
print(square(5))
print(add(5, 3))
print(complexOperation(5))
print(operate(6, 7) { $0 * $1 })
let double = makeMultiplier(2)
print(double(5))
print(doubled)
print(filtered)Swift doesn't have built-in scope functions like Kotlin, but similar patterns can be implemented with closures.
- with: Custom
withfunction - also: Custom
alsofunction - let: Using closures
- takeIf: Custom function
- Closures: For scoping
// Scope Functions in Swift
// Swift doesn't have built-in scope functions like Kotlin
// But we can use closures and with/run patterns
struct Person {
var name: String
var age: Int
var city: String
}
// let - execute block (using closure)
func processPerson() {
var person = Person(name: "Alice", age: 25, city: "NYC")
let result = { () -> Person in
print("Name: \(person.name)")
person.age += 1
return person
}()
print("Updated age: \(result.age)")
}
// apply - configure object (using with)
func with<T, R>(_ obj: T, _ block: (inout T) -> R) -> R {
var mutable = obj
return block(&mutable)
}
let updated = with(Person(name: "Alice", age: 25, city: "NYC")) { person in
person.age = 26
person.city = "SF"
}
print(updated)
// also - perform additional operations
func also<T>(_ obj: T, _ block: (T) -> Void) -> T {
block(obj)
return obj
}
let person = also(Person(name: "Alice", age: 25, city: "NYC")) { p in
print("Before: \(p)")
}
// take-if equivalent
func takeIf<T>(_ value: T, predicate: (T) -> Bool) -> T? {
return predicate(value) ? value : nil
}
let adult = takeIf(25) { $0 >= 18 }
print(adult ?? 0)Extensions in Swift add new functionality to existing types without subclassing.
- Extension:
extension String { } - Computed properties:
var property: Type { } - Methods: Add instance and class methods
- Protocol extensions:
extension Collection { } - Default implementations: Provide default behavior
// Extension Functions in Swift
// String extensions
extension String {
func isEmail() -> Bool {
return contains("@") && contains(".")
}
func addPrefix(_ prefix: String) -> String {
return prefix + self
}
func wordCount() -> Int {
return components(separatedBy: .whitespacesAndNewlines)
.filter { !$0.isEmpty }
.count
}
}
// Numeric extensions
extension Int {
func isEven() -> Bool {
return self % 2 == 0
}
func isOdd() -> Bool {
return self % 2 != 0
}
}
// Array extensions
extension Array {
func secondOrNil() -> Element? {
return count >= 2 ? self[1] : nil
}
}
// Usage
let email = "test@example.com"
print(email.isEmail())
let greeting = "Hello".addPrefix("Greeting: ")
print(greeting)
print(5.isEven())
print("Hello World".wordCount())
let numbers = [1, 2, 3]
print(numbers.secondOrNil() ?? "nil")
// Protocol extension
extension Collection {
func isNotEmpty() -> Bool {
return !isEmpty
}
}
print([1, 2, 3].isNotEmpty())Type aliases provide alternative names for existing types, improving readability and reusability.
- Definition:
typealias Name = OriginalType - Function types:
typealias Operation = (Int, Int) -> Int - Complex types:
typealias UserMap = [String: User] - Tuple types:
typealias Pair = (String, Int) - Generic types:
typealias Result<T> = (T) -> Void
// Type Aliases in Swift
// Type aliases for complex types
typealias Operation = (Int, Int) -> Int
typealias UserMap = [String: User]
typealias UserId = Int
typealias UserName = String
typealias ResultCallback = (Result<String, Error>) -> Void
// Using type aliases
struct User {
let id: UserId
let name: UserName
}
func execute(_ op: Operation, _ a: Int, _ b: Int) -> Int {
return op(a, b)
}
// Function type alias
typealias OperationFn = (Int, Int) -> Int
func add(_ a: Int, _ b: Int) -> Int { return a + b }
func multiply(_ a: Int, _ b: Int) -> Int { return a * b }
// Tuple type alias
typealias UserInfo = (name: String, age: Int)
// Usage
let addOp: Operation = { $0 + $1 }
let multiplyOp: Operation = { $0 * $1 }
print(execute(addOp, 5, 3))
print(execute(multiplyOp, 5, 3))
let addFn: OperationFn = add
let multiplyFn: OperationFn = multiply
print(addFn(5, 3))
print(multiplyFn(5, 3))
var users: UserMap = [:]
users[1] = User(id: 1, name: "Alice")
users[2] = User(id: 2, name: "Bob")
if let user = users[1] {
print("User: \(user.name)")
}
let userInfo: UserInfo = (name: "Alice", age: 25)
print("Name: \(userInfo.name), Age: \(userInfo.age)")Swift uses @inline attributes for performance optimization, though the compiler handles most inlining.
- @inline(__always): Force inline
- @inline(never): Prevent inline
- Generic functions: Often inlined
- Performance: Reduces function call overhead
- Compiler optimization: Automatic inlining
// Inline Functions in Swift
// Swift uses @inline attribute for performance optimization
// Inline function
@inline(__always)
func square(_ x: Int) -> Int {
return x * x
}
// Inline always
@inline(__always)
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
// Inline never
@inline(never)
func complexCalculation(_ x: Int) -> Int {
let y = x * 2
return y + 10
}
// Generic inline function
@inline(__always)
func process<T>(_ value: T, transform: (T) -> T) -> T {
return transform(value)
}
// Measurement macro (compile-time)
func measureTime(_ block: () -> Void) {
let start = CFAbsoluteTimeGetCurrent()
block()
let end = CFAbsoluteTimeGetCurrent()
print("Time: \(end - start)s")
}
// Usage
print(square(5))
print(add(5, 3))
print(complexCalculation(5))
let result = process(5) { $0 * 2 }
print(result)
measureTime {
Thread.sleep(forTimeInterval: 0.1)
print("Operation completed")
}Higher-order functions take functions as parameters or return functions. Swift supports them natively.
- Function parameters:
func operate(_ operation: (Int, Int) -> Int) - Returning functions:
func getMultiplier() -> (Int) -> Int - Map, filter, reduce: Built-in HOFs
- Composition: Combine functions
- Closures: First-class citizens
// Higher-Order Functions in Swift
// Function that takes a function as parameter
func applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
// Function that returns a function
func getMultiplier(_ factor: Int) -> (Int) -> Int {
return { x in
return x * factor
}
}
// Function composition
func compose<T, U, V>(_ f: @escaping (U) -> V, _ g: @escaping (T) -> U) -> (T) -> V {
return { x in
return f(g(x))
}
}
// Higher-order function with multiple closures
func process(_ value: Int, transform: (Int) -> Int, filter: (Int) -> Bool) -> Int? {
return filter(value) ? transform(value) : nil
}
// Usage
let result = applyOperation(10, 20) { $0 + $1 }
print(result)
let double = getMultiplier(2)
print(double(5))
let square = { (x: Int) -> Int in x * x }
let addTen = { (x: Int) -> Int in x + 10 }
let squareThenAddTen = compose(addTen, square)
print(squareThenAddTen(5))
let processed = process(5, transform: { $0 * 2 }, filter: { $0 > 3 })
print(processed ?? 0)
// Built-in higher-order functions
let numbers = [1, 2, 3, 4, 5]
let squared = numbers.map { $0 * $0 }
let even = numbers.filter { $0 % 2 == 0 }
let sum = numbers.reduce(0, +)
print(squared)
print(even)
print(sum)Async/await in Swift provides structured concurrency for asynchronous programming, available from Swift 5.5.
- async:
func fetch() async -> String - await:
let result = await fetch() - Task:
Task { } - Async sequences:
AsyncStream - Task groups:
withTaskGroup
// Async/Await in Swift
import Foundation
// Basic async function
func fetchData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
return "Data loaded"
}
// Async function with timeout
func fetchWithTimeout() async throws -> String {
let timeout = Task {
try await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds
return "Timeout"
}
let data = Task {
try await fetchData()
}
let result = await withTaskGroup(of: String.self) { group in
group.addTask { await timeout.result ?? "" }
group.addTask { await data.result ?? "" }
var firstResult = ""
for await value in group {
firstResult = value
group.cancelAll()
break
}
return firstResult
}
return result
}
// Multiple async tasks
func parallelTasks() async -> [String] {
async let task1 = fetchData()
async let task2 = fetchData()
async let task3 = fetchData()
let results = await [task1, task2, task3]
return results
}
// Async with timeout and error handling
func asyncWithTimeout() async {
do {
let result = try await withTimeout(seconds: 0.5) {
try await fetchData()
}
print("Result: \(result)")
} catch {
print("Timeout or error: \(error)")
}
}
func withTimeout<T>(seconds: Double, operation: @escaping () async throws -> T) async throws -> T {
try await withThrowingTaskGroup(of: T.self) { group in
group.addTask {
try await operation()
}
group.addTask {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
throw NSError(domain: "Timeout", code: 1, userInfo: nil)
}
let result = try await group.next()!
group.cancelAll()
return result
}
}
// Async sequence (stream)
func asyncStream() -> AsyncStream<String> {
return AsyncStream { continuation in
Task {
for i in 1...5 {
try? await Task.sleep(nanoseconds: 100_000_000)
continuation.yield("Item \(i)")
}
continuation.finish()
}
}
}
// Usage
Task {
let data = await fetchData()
print(data)
let results = await parallelTasks()
print("Results: \(results)")
await asyncWithTimeout()
for await item in asyncStream() {
print(item)
}
}Iterators provide sequential access to elements, and sequences define the iteration protocol.
- IteratorProtocol:
mutating func next() -> Element? - Sequence:
func makeIterator() -> Iterator - Lazy sequences:
.lazy - Infinite sequences: Can be infinite
- Sequence adapters:
map,filter,drop
// Iterators and Sequences in Swift
// Basic iterator
let numbers = [1, 2, 3, 4, 5]
// Map, filter, reduce
let doubled = numbers.map { $0 * 2 }
let evens = numbers.filter { $0 % 2 == 0 }
let sum = numbers.reduce(0, +)
print("Doubled: \(doubled)")
print("Evens: \(evens)")
print("Sum: \(sum)")
// Custom iterator
struct Counter: Sequence {
let max: Int
func makeIterator() -> CounterIterator {
return CounterIterator(max: max)
}
}
struct CounterIterator: IteratorProtocol {
var current = 0
let max: Int
mutating func next() -> Int? {
current += 1
return current <= max ? current : nil
}
}
let counter = Counter(max: 10)
for num in counter {
print(num)
}
// Lazy sequences
let lazySequence = (1...10).lazy
.map { x -> Int in
print("Mapping: \(x)")
return x * 2
}
.filter { x -> Bool in
print("Filtering: \(x)")
return x % 3 == 0
}
let result = Array(lazySequence.prefix(3))
print("Result: \(result)")
// Sequence adapters
let processed = (1...10)
.dropFirst(2)
.prefix(5)
.map { $0 * 2 }
.filter { $0 % 3 == 0 }
print("Processed: \(Array(processed))")
// Infinite sequence
struct FibonacciSequence: Sequence {
func makeIterator() -> FibonacciIterator {
return FibonacciIterator()
}
}
struct FibonacciIterator: IteratorProtocol {
var a = 0
var b = 1
mutating func next() -> Int? {
let value = a
let temp = a + b
a = b
b = temp
return value
}
}
let fib = FibonacciSequence()
let firstTenFib = Array(fib.prefix(10))
print("Fibonacci: \(firstTenFib)")Swift uses actors and async streams for channel-like communication and concurrency.
- Actors:
actor Counter - AsyncStream: Produce values over time
- AsyncSequence: Iterate over async values
- Task groups: Group related tasks
- Continuation:
withCheckedContinuation
// Channels and Concurrency in Swift
import Foundation
// Actor for thread-safe state
actor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
// AsyncStream as channel
func createChannel() -> AsyncStream<Int> {
return AsyncStream { continuation in
Task {
for i in 1...5 {
try? await Task.sleep(nanoseconds: 100_000_000)
continuation.yield(i)
}
continuation.finish()
}
}
}
// AsyncSequence for streaming
struct NumberStream: AsyncSequence {
typealias Element = Int
let max: Int
func makeAsyncIterator() -> NumberStreamIterator {
return NumberStreamIterator(max: max)
}
}
struct NumberStreamIterator: AsyncIteratorProtocol {
var current = 0
let max: Int
mutating func next() async -> Int? {
current += 1
if current > max {
return nil
}
try? await Task.sleep(nanoseconds: 100_000_000)
return current
}
}
// Task group for parallel processing
func processNumbers() async {
await withTaskGroup(of: String.self) { group in
for i in 1...5 {
group.addTask {
try? await Task.sleep(nanoseconds: 100_000_000)
return "Task \(i) completed"
}
}
for await result in group {
print(result)
}
}
}
// Usage
Task {
// Actor example
let counter = Counter()
await counter.increment()
await counter.increment()
print("Counter: \(await counter.getValue())")
// Channel example
for await value in createChannel() {
print("Channel: \(value)")
}
// Async sequence
for await value in NumberStream(max: 5) {
print("Stream: \(value)")
}
// Task group
await processNumbers()
}Enums in Swift are powerful with associated values, pattern matching, and exhaustive switch handling.
- Associated values:
case success(Int) - Pattern matching:
switch - Guard case:
guard case - If case:
if case - Recursive enums:
indirect enum
// Enums and Pattern Matching in Swift
// Enum with associated values
enum Result<T> {
case success(T)
case error(String)
case loading
}
// Enum with methods
enum Status {
case success(Int)
case error(String)
case loading
func isSuccess() -> Bool {
switch self {
case .success:
return true
default:
return false
}
}
func getCode() -> Int? {
if case .success(let code) = self {
return code
}
return nil
}
}
// Discriminated union pattern
enum UIState {
case success(data: String)
case error(message: String)
case loading
case idle
}
extension UIState {
func isLoading() -> Bool {
if case .loading = self {
return true
}
return false
}
func getData() -> String? {
if case .success(let data) = self {
return data
}
return nil
}
}
// Pattern matching with guards
func processNumber(_ number: Int) {
switch number {
case let n where n < 0:
print("Negative: \(n)")
case 0:
print("Zero")
case let n where n > 0:
print("Positive: \(n)")
default:
print("Unknown")
}
}
// If let and guard let
func processOptional(_ value: Int?) {
if let unwrapped = value {
print("Value: \(unwrapped)")
}
guard let unwrapped = value else {
print("Value is nil")
return
}
print("Guard value: \(unwrapped)")
}
// Usage
let result = Result.success(200)
let status = Status.success(200)
if case .success(let code) = status {
print("Success code: \(code)")
}
switch result {
case .success(let value):
print("Success: \(value)")
case .error(let message):
print("Error: \(message)")
case .loading:
print("Loading...")
}
processNumber(-5)
processOptional(42)
processOptional(nil)Generics allow writing flexible, reusable functions and types that can work with any type.
- Generic functions:
func swap<T>(_ a: T, _ b: T) - Generic types:
struct Box<T> - Constraints:
<T: Numeric> - Associated types:
associatedtype Item - Protocol generics:
protocol Repository { associatedtype Item }
// Generics in Swift
// Generic struct
struct Box<T> {
let value: T
func getValue() -> T {
return value
}
}
// Generic function
func swap<T>(_ a: T, _ b: T) -> (T, T) {
return (b, a)
}
// Generic with constraints
func sumNumbers<T: Numeric>(_ items: [T]) -> T {
return items.reduce(T.zero, +)
}
// Generic with multiple constraints
protocol Displayable {
func display() -> String
}
protocol Countable {
func count() -> Int
}
func process<T: Displayable & Countable>(_ item: T) {
print(item.display())
print("Count: \(item.count())")
}
// Associated types in protocols
protocol Repository {
associatedtype Item
func get(id: Int) -> Item?
func save(item: Item)
}
struct UserRepository: Repository {
typealias Item = User
func get(id: Int) -> User? {
return User(id: id, name: "Alice")
}
func save(item: User) {
print("Saving user: \(item.name)")
}
}
// Variance - Covariant (using associated types)
protocol Producer {
associatedtype T
func produce() -> T
}
// Contravariant
protocol Consumer {
associatedtype T
func consume(item: T)
}
// Usage
let boxInt = Box(value: 42)
let boxString = Box(value: "Hello")
print(boxInt.getValue())
print(boxString.getValue())
let swapped = swap(1, 2)
print("Swapped: \(swapped.0), \(swapped.1)")
let numbers = [1, 2, 3, 4, 5]
print("Sum: \(sumNumbers(numbers))")
struct User {
let id: Int
let name: String
}
struct MyData {
let value: String
}
extension MyData: Displayable, Countable {
func display() -> String {
return "Data: \(value)"
}
func count() -> Int {
return value.count
}
}
let data = MyData(value: "Hello")
process(data)Protocols define blueprints of methods and properties, and delegation is a design pattern using protocols.
- Protocol:
protocol Delegate - Delegation: One object delegates tasks
- Weak delegates:
weak var delegate - Optional methods:
@objc optional - Protocol extensions: Default implementations
// Protocols and Delegation in Swift
// Protocol definition
protocol Repository {
func getData() -> String
func saveData(_ data: String)
}
// Implementation
class DatabaseRepository: Repository {
func getData() -> String {
return "Data from database"
}
func saveData(_ data: String) {
print("Saving to database: \(data)")
}
}
// Delegation using protocol
protocol DataSourceDelegate: AnyObject {
func dataDidLoad(_ data: [String])
func dataDidFail(with error: Error)
}
// Class using delegate
class DataSource {
weak var delegate: DataSourceDelegate?
func loadData() {
// Simulate async loading
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
DispatchQueue.main.async {
self.delegate?.dataDidLoad(["Item 1", "Item 2", "Item 3"])
}
}
}
}
// Delegate implementation
class ViewController: DataSourceDelegate {
let dataSource = DataSource()
init() {
dataSource.delegate = self
dataSource.loadData()
}
func dataDidLoad(_ data: [String]) {
print("Data loaded: \(data)")
}
func dataDidFail(with error: Error) {
print("Error: \(error)")
}
}
// Property delegation using property wrappers
@propertyWrapper
struct Lazy<Value> {
private var storage: Value?
private let initializer: () -> Value
init(wrappedValue: @autoclosure @escaping () -> Value) {
self.initializer = wrappedValue
}
var wrappedValue: Value {
mutating get {
if let value = storage {
return value
}
let value = initializer()
storage = value
return value
}
set {
storage = newValue
}
}
}
class LazyExample {
@Lazy(wrappedValue: expensiveComputation())
var data: String
static func expensiveComputation() -> String {
print("Computing expensive data...")
return "Expensive Result"
}
}
// Usage
let vc = ViewController()
var lazyExample = LazyExample()
print(lazyExample.data)
print(lazyExample.data) // CachedSingleton pattern ensures a class has only one instance. It's implemented with a static constant.
- Static constant:
static let shared = Singleton() - Private init:
private init() - Lazy initialization:
static var shared: Singleton = () - Thread safety: Guaranteed by Swift
- Global access:
Singleton.shared
// Singleton Pattern in Swift
// Singleton using static constant
class AppConfig {
static let shared = AppConfig()
private init() {} // Private initializer
var apiUrl = "https://api.example.com"
var timeout = 5000
func printConfig() {
print("API URL: \(apiUrl)")
print("Timeout: \(timeout)")
}
}
// Singleton with lazy initialization
class UserManager {
static var shared: UserManager = {
let instance = UserManager()
return instance
}()
private init() {}
private var users: [String] = []
func addUser(_ name: String) {
users.append(name)
}
func getUsers() -> [String] {
return users
}
}
// Singleton with dispatch_once (using static)
class DatabaseManager {
static let shared = DatabaseManager()
private init() {
// Initialize database connection
print("Database initialized")
}
func query(_ sql: String) -> String {
return "Executing: \(sql)"
}
}
// Usage
let config = AppConfig.shared
config.printConfig()
let manager = UserManager.shared
manager.addUser("Alice")
manager.addUser("Bob")
print("Users: \(manager.getUsers())")
let db = DatabaseManager.shared
print(db.query("SELECT * FROM users"))Builder pattern constructs complex objects step by step using a fluent interface.
- Builder class: Constructs objects
- Fluent interface: Method chaining
- Director: Orchestrates construction
- Result builders: DSL for building
- Product: Final constructed object
// Builder Pattern and DSL in Swift
// Builder pattern
struct User {
let name: String
let age: Int
let email: String
let city: String
}
class UserBuilder {
private var name: String = ""
private var age: Int = 0
private var email: String = ""
private var city: String = "Unknown"
func setName(_ name: String) -> UserBuilder {
self.name = name
return self
}
func setAge(_ age: Int) -> UserBuilder {
self.age = age
return self
}
func setEmail(_ email: String) -> UserBuilder {
self.email = email
return self
}
func setCity(_ city: String) -> UserBuilder {
self.city = city
return self
}
func build() -> User {
return User(name: name, age: age, email: email, city: city)
}
}
// Fluent interface
struct Query {
let table: String
let fields: [String]
let conditions: [String]
let orderBy: [String]
let limit: Int?
static func from(_ table: String) -> QueryBuilder {
return QueryBuilder(table: table)
}
}
class QueryBuilder {
private var table: String
private var fields: [String] = []
private var conditions: [String] = []
private var orderBy: [String] = []
private var limit: Int?
init(table: String) {
self.table = table
}
func select(_ fields: String...) -> QueryBuilder {
self.fields = fields
return self
}
func `where`(_ condition: String) -> QueryBuilder {
conditions.append(condition)
return self
}
func order(by field: String, ascending: Bool = true) -> QueryBuilder {
let direction = ascending ? "ASC" : "DESC"
orderBy.append("\(field) \(direction)")
return self
}
func limit(_ count: Int) -> QueryBuilder {
self.limit = count
return self
}
func build() -> Query {
return Query(table: table, fields: fields, conditions: conditions, orderBy: orderBy, limit: limit)
}
func execute() -> String {
var query = "SELECT "
if fields.isEmpty {
query += "*"
} else {
query += fields.joined(separator: ", ")
}
query += " FROM \(table)"
if !conditions.isEmpty {
query += " WHERE \(conditions.joined(separator: " AND "))"
}
if !orderBy.isEmpty {
query += " ORDER BY \(orderBy.joined(separator: ", "))"
}
if let limit = limit {
query += " LIMIT \(limit)"
}
return query
}
}
// Result builders (DSL)
@resultBuilder
struct HTMLBuilder {
static func buildBlock(_ components: String...) -> String {
return components.joined()
}
}
func html(@HTMLBuilder _ content: () -> String) -> String {
return "<html>\(content())</html>"
}
func body(@HTMLBuilder _ content: () -> String) -> String {
return "<body>\(content())</body>"
}
func h1(_ text: String) -> String {
return "<h1>\(text)</h1>"
}
func p(_ text: String) -> String {
return "<p>\(text)</p>"
}
// Usage
let user = UserBuilder()
.setName("Alice")
.setAge(25)
.setEmail("alice@example.com")
.setCity("NYC")
.build()
print(user)
let query = Query.from("users")
.select("name", "age")
.where("age > 18")
.order(by: "name", ascending: true)
.limit(10)
.execute()
print(query)
let page = html {
body {
h1("Welcome")
p("This is a paragraph")
}
}
print(page)Macros (Swift 5.9+) generate code at compile time, and attributes provide metadata.
- Macros:
@freestanding,@attached - Attributes:
@available,@discardableResult - Property wrappers:
@propertyWrapper - Result builders:
@resultBuilder - Custom attributes: Create custom attributes
// Macros and Attributes in Swift
// Basic macro (Swift 5.9+)
// Note: Macros are a Swift 5.9+ feature
// Stringify macro example
@freestanding(expression)
macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MyMacros", type: "StringifyMacro")
// Usage: let (result, string) = #stringify(42)
// print(result) // 42
// print(string) // "42"
// Attribute macros
@available(iOS 13.0, *)
func newFeature() {
print("This is a new feature")
}
// Deprecated attribute
@available(*, deprecated, message: "Use newFunction instead")
func oldFunction() {
print("Old function")
}
// Custom attribute
@propertyWrapper
struct DeprecatedMessage {
private var value: String
init(wrappedValue: String) {
self.value = wrappedValue
}
var wrappedValue: String {
get { value }
set { value = newValue }
}
}
// Result builder attribute
@resultBuilder
struct StringBuilder {
static func buildBlock(_ components: String...) -> String {
return components.joined(separator: " ")
}
}
func buildString(@StringBuilder _ content: () -> String) -> String {
return content()
}
// Usage
let message = buildString {
"Hello"
"World"
"Swift"
}
print(message)
// Conditional compilation
#if DEBUG
print("Debug mode")
#else
print("Release mode")
#endif
// Platform-specific code
#if os(iOS)
print("Running on iOS")
#elseif os(macOS)
print("Running on macOS")
#endif
// Warning and error macros
#warning("This is a warning")
// #error("This is an error")Reflection in Swift is provided through Mirror and KeyPath for inspecting types and accessing properties.
- Mirror: Reflect on types
- KeyPath: Type-safe property access
- Dynamic member lookup:
@dynamicMemberLookup - Codable: Serialization/deserialization
- Type checking:
type(of:)
// Reflection and Type Information in Swift
import Foundation
// Class for reflection examples
class Person {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func greet() -> String {
return "Hello, my name is \(name)"
}
}
// Type checking
func checkType<T, U>(_ type1: T.Type, _ type2: U.Type) -> Bool {
return type1 == type2
}
// Mirror for reflection
func reflectObject(_ obj: Any) {
let mirror = Mirror(reflecting: obj)
print("Type: \(mirror.subjectType)")
print("Children:")
for child in mirror.children {
print(" \(child.label ?? "?") : \(child.value)")
}
}
// Property access with KeyPath
struct User {
let name: String
let age: Int
let email: String
}
func getProperty<T, V>(_ obj: T, keyPath: KeyPath<T, V>) -> V {
return obj[keyPath: keyPath]
}
// Dynamic member lookup
@dynamicMemberLookup
struct DynamicObject {
private var storage: [String: Any] = [:]
subscript(dynamicMember member: String) -> Any? {
get { storage[member] }
set { storage[member] = newValue }
}
}
// Codable for serialization
struct SerializablePerson: Codable {
let name: String
let age: Int
let email: String
}
// Usage
let person = Person(name: "Alice", age: 25)
reflectObject(person)
let user = User(name: "Alice", age: 25, email: "alice@example.com")
let userName = getProperty(user, keyPath: .name)
print("User name: \(userName)")
// Dynamic member lookup
var obj = DynamicObject()
obj.name = "Alice"
obj.age = 25
print(obj.name ?? "nil")
print(obj.age ?? 0)
// Codable serialization
let serializable = SerializablePerson(name: "Alice", age: 25, email: "alice@example.com")
let encoder = JSONEncoder()
if let data = try? encoder.encode(serializable) {
let json = String(data: data, encoding: .utf8) ?? ""
print("Serialized: \(json)")
}
let decoder = JSONDecoder()
if let decoded = try? decoder.decode(SerializablePerson.self, from: Data(json.utf8)) {
print("Decoded: \(decoded)")
}Reverse a string using reversed() or manual iteration.
- Built-in:
String(str.reversed()) - Manual: Iterate from end to start
- Reduce:
reducewith string concatenation - Complexity: O(n) time
// Reverse a string in Swift
func reverseString(_ str: String) -> String {
return String(str.reversed())
}
print(reverseString("hello")) // "olleh"
// Manual implementation
func reverseStringManual(_ str: String) -> String {
var result = ""
for char in str {
result = String(char) + result
}
return result
}
print(reverseStringManual("hello")) // "olleh"
// Using reduce
func reverseStringReduce(_ str: String) -> String {
return str.reduce("") { String($1) + $0 }
}
print(reverseStringReduce("hello")) // "olleh"Check if a string is a palindrome using reversed() or two-pointer approach.
- reversed():
cleaned == String(cleaned.reversed()) - Two-pointer: Compare from both ends
- Case insensitive:
lowercased() - Ignoring non-alphanumeric:
filter { $0.isLetter || $0.isNumber }
// Check palindrome in Swift
func isPalindrome(_ str: String) -> Bool {
let cleaned = str.lowercased().filter { $0.isLetter || $0.isNumber }
return cleaned == String(cleaned.reversed())
}
print(isPalindrome("racecar")) // true
print(isPalindrome("hello")) // false
// Two-pointer approach
func isPalindromeTwoPointer(_ str: String) -> Bool {
let chars = Array(str.lowercased().filter { $0.isLetter || $0.isNumber })
var left = 0
var right = chars.count - 1
while left < right {
if chars[left] != chars[right] {
return false
}
left += 1
right -= 1
}
return true
}
print(isPalindromeTwoPointer("A man a plan a canal Panama")) // trueFind maximum using max() or manual iteration.
- Built-in:
arr.max() - Manual: Iterate and track max
- Reduce:
reduce(Int.min, max) - Complexity: O(n) time
// Find max in array in Swift
func findMax(_ arr: [Int]) -> Int? {
return arr.max()
}
print(findMax([1, 5, 3, 9, 2]) ?? 0) // 9
// Manual implementation
func findMaxManual(_ arr: [Int]) -> Int? {
guard !arr.isEmpty else { return nil }
var maxVal = arr[0]
for num in arr {
if num > maxVal {
maxVal = num
}
}
return maxVal
}
print(findMaxManual([1, 5, 3, 9, 2]) ?? 0) // 9
// Using reduce
func findMaxReduce(_ arr: [Int]) -> Int? {
return arr.reduce(Int.min) { max($0, $1) }
}Remove duplicates using Set or filter with contains.
- Set:
Array(Set(arr)) - Order preserved:
filter { seen.insert($0).inserted } - Complexity: O(n) time
- Hashable: Elements must be Hashable
// Remove duplicates in Swift
func removeDuplicates<T: Hashable>(_ arr: [T]) -> [T] {
return Array(Set(arr))
}
print(removeDuplicates([1, 2, 2, 3, 3, 4])) // [1, 2, 3, 4]
// Preserving order
func removeDuplicatesOrder<T: Hashable>(_ arr: [T]) -> [T] {
var seen = Set<T>()
return arr.filter { seen.insert($0).inserted }
}
print(removeDuplicatesOrder([1, 2, 2, 3, 3, 4])) // [1, 2, 3, 4]
// Using reduce
func removeDuplicatesReduce<T: Hashable>(_ arr: [T]) -> [T] {
return arr.reduce(into: []) { result, element in
if !result.contains(element) {
result.append(element)
}
}
}Merge arrays using + operator or append(contentsOf:).
- + operator:
arr1 + arr2 - append:
arr1.append(contentsOf: arr2) - Unique merge:
Array(Set(arr1 + arr2)) - Complexity: O(n) time
// Merge arrays in Swift
func mergeArrays<T>(_ arr1: [T], _ arr2: [T]) -> [T] {
return arr1 + arr2
}
print(mergeArrays([1, 2], [3, 4])) // [1, 2, 3, 4]
// Merge and remove duplicates
func mergeUnique<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
return Array(Set(arr1 + arr2))
}
print(mergeUnique([1, 2, 3], [3, 4, 5])) // [1, 2, 3, 4, 5]
// Preserving order
func mergeUniqueOrder<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
var seen = Set<T>()
return (arr1 + arr2).filter { seen.insert($0).inserted }
}Convert using Int() or Double() initializers.
- Int:
Int(str) - Double:
Double(str) - Safe: Returns optional
- Error handling: Check for nil
// Convert string to number in Swift
func stringToNumber(_ str: String) -> Int? {
return Int(str)
}
print(stringToNumber("42") ?? 0) // 42
// Safe conversion
func stringToNumberSafe(_ str: String) -> Int? {
return Int(str) ?? nil
}
print(stringToNumberSafe("42") ?? 0) // 42
print(stringToNumberSafe("invalid") ?? 0) // 0
// Convert to Double
func stringToDouble(_ str: String) -> Double? {
return Double(str)
}
print(stringToDouble("42.5") ?? 0) // 42.5Iterate using for-in, keys, values, or forEach.
- for-in:
for (key, value) in dict - keys:
for key in dict.keys - values:
for value in dict.values - forEach:
dict.forEach
// Loop through dictionary in Swift
let dict = ["name": "Alice", "age": "25", "city": "NYC"]
// Using for-in
for (key, value) in dict {
print("\(key) => \(value)")
}
// Using keys
for key in dict.keys {
print("\(key) => \(dict[key] ?? "")")
}
// Using values
for value in dict.values {
print(value)
}
// Using forEach
dict.forEach { key, value in
print("\(key) => \(value)")
}
// Sorting keys
for key in dict.keys.sorted() {
print("\(key) => \(dict[key] ?? "")")
}Delay using DispatchQueue, Timer, or async/await.
- DispatchQueue:
asyncAfter(deadline: .now() + seconds) - Timer:
scheduledTimer(withTimeInterval:) - async/await:
Task.sleep(nanoseconds:) - RunLoop:
RunLoop.current.run(until:)
// Delay function execution in Swift
import Foundation
// Using DispatchQueue
func delayedExecution(seconds: Double, block: @escaping () -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + seconds) {
block()
}
}
// Using Timer
func delayedTimer(seconds: TimeInterval, block: @escaping () -> Void) {
Timer.scheduledTimer(withTimeInterval: seconds, repeats: false) { _ in
block()
}
}
// Using async/await
func delay(_ seconds: UInt64) async throws {
try await Task.sleep(nanoseconds: seconds * 1_000_000_000)
}
// Usage
delayedExecution(seconds: 2) {
print("After 2 seconds (DispatchQueue)")
}
delayedTimer(seconds: 2) {
print("After 2 seconds (Timer)")
}
Task {
try? await delay(2)
print("After 2 seconds (async/await)")
}
// Keep main thread alive
RunLoop.current.run(until: Date().addingTimeInterval(3))HTTP GET using URLSession with completion or async/await.
- URLSession:
dataTask(with:completionHandler:) - Async/await:
URLSession.shared.data(from:) - JSON decoding:
JSONDecoder() - Error handling:
try-catch
// HTTP GET request in Swift
import Foundation
// Using URLSession
func fetchData(url: String, completion: @escaping (Result<Data, Error>) -> Void) {
guard let url = URL(string: url) else {
completion(.failure(NSError(domain: "InvalidURL", code: -1)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
completion(.failure(NSError(domain: "NoData", code: -2)))
return
}
completion(.success(data))
}
task.resume()
}
// Async/await version
func fetchDataAsync(url: String) async throws -> Data {
guard let url = URL(string: url) else {
throw NSError(domain: "InvalidURL", code: -1)
}
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
// Decode JSON
struct User: Codable {
let id: Int
let name: String
let email: String
}
func fetchUser(id: Int) async throws -> User {
let url = "https://jsonplaceholder.typicode.com/users/\(id)"
let data = try await fetchDataAsync(url: url)
let user = try JSONDecoder().decode(User.self, from: data)
return user
}
// Usage
fetchData(url: "https://jsonplaceholder.typicode.com/users/1") { result in
switch result {
case .success(let data):
let json = String(data: data, encoding: .utf8) ?? ""
print("Data: \(json)")
case .failure(let error):
print("Error: \(error)")
}
}
Task {
do {
let user = try await fetchUser(id: 1)
print("User: \(user.name)")
} catch {
print("Error: \(error)")
}
}
// Keep main thread alive
RunLoop.current.run(until: Date().addingTimeInterval(2))Create a Deferred using Deferred class with resolve and reject.
- Deferred class: Custom implementation
- resolve: Set success value
- reject: Set error
- then: Add callback
// Create a promise-like Deferred in Swift
import Foundation
// Deferred implementation
class Deferred<T> {
private var value: T?
private var error: Error?
private var state: State = .pending
private var callbacks: [(Result<T, Error>) -> Void] = []
private let lock = NSLock()
enum State {
case pending
case resolved
case rejected
}
func resolve(_ value: T) {
lock.lock()
defer { lock.unlock() }
guard state == .pending else { return }
state = .resolved
self.value = value
callbacks.forEach { $0(.success(value)) }
callbacks.removeAll()
}
func reject(_ error: Error) {
lock.lock()
defer { lock.unlock() }
guard state == .pending else { return }
state = .rejected
self.error = error
callbacks.forEach { $0(.failure(error)) }
callbacks.removeAll()
}
func then(_ callback: @escaping (Result<T, Error>) -> Void) {
lock.lock()
defer { lock.unlock() }
switch state {
case .pending:
callbacks.append(callback)
case .resolved:
callback(.success(value!))
case .rejected:
callback(.failure(error!))
}
}
}
// Promise-like function
func createDeferred(shouldResolve: Bool) -> Deferred<String> {
let deferred = Deferred<String>()
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
if shouldResolve {
deferred.resolve("Success!")
} else {
deferred.reject(NSError(domain: "DeferredError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed!"]))
}
}
return deferred
}
// Usage
let deferred = createDeferred(shouldResolve: true)
deferred.then { result in
switch result {
case .success(let value):
print("Result: \(value)")
case .failure(let error):
print("Error: \(error)")
}
}
// Keep main thread alive
RunLoop.current.run(until: Date().addingTimeInterval(2))Calculate factorial using recursion or iteration.
- Recursive:
n * factorial(n-1) - Iterative: Loop with multiplication
- Base case:
n <= 1 - Edge cases: 0! = 1
// Factorial in Swift
func factorial(_ n: Int) -> Int {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
print(factorial(5)) // 120
// Iterative version
func factorialIterative(_ n: Int) -> Int {
var result = 1
for i in 2...n {
result *= i
}
return result
}
print(factorialIterative(5)) // 120
// Using reduce
func factorialReduce(_ n: Int) -> Int {
return (1...n).reduce(1, *)
}
print(factorialReduce(5)) // 120Calculate Fibonacci using recursion, iteration, or memoization.
- Recursive:
fib(n-1) + fib(n-2) - Iterative: Loop with variables
- Memoization: Cache results in dictionary
- Complexity: O(n) with memoization
// Fibonacci in Swift
func fibonacci(_ n: Int) -> Int {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
print(fibonacci(8)) // 21
// Iterative version
func fibonacciIterative(_ n: Int) -> Int {
if n <= 1 {
return n
}
var a = 0, b = 1
for _ in 2...n {
let temp = a + b
a = b
b = temp
}
return b
}
print(fibonacciIterative(8)) // 21
// Memoized version
var fibCache: [Int: Int] = [:]
func fibonacciMemo(_ n: Int) -> Int {
if n <= 1 {
return n
}
if let cached = fibCache[n] {
return cached
}
let result = fibonacciMemo(n - 1) + fibonacciMemo(n - 2)
fibCache[n] = result
return result
}
print(fibonacciMemo(8)) // 21FizzBuzz using if-else or switch with modulo operations.
- Modulo: Check divisibility by 3, 5, 15
- Order: Check 15 first
- Range:
for i in 1...n - Return array: Collect results
// FizzBuzz in Swift
func fizzbuzz(_ n: Int) {
for i in 1...n {
if i % 15 == 0 {
print("FizzBuzz")
} else if i % 3 == 0 {
print("Fizz")
} else if i % 5 == 0 {
print("Buzz")
} else {
print(i)
}
}
}
fizzbuzz(15)
// Return as array
func fizzbuzzArray(_ n: Int) -> [String] {
return (1...n).map { i in
switch (i % 3 == 0, i % 5 == 0) {
case (true, true): return "FizzBuzz"
case (true, false): return "Fizz"
case (false, true): return "Buzz"
default: return String(i)
}
}
}
print(fizzbuzzArray(15))Find missing number using formula or XOR method.
- Formula:
total - sum - XOR: XOR all numbers and indices
- Complexity: O(n) time
- Edge cases: Empty array, missing first or last
// Find missing number in Swift
func findMissing(_ arr: [Int]) -> Int {
let n = arr.count + 1
let total = n * (n + 1) / 2
let sum = arr.reduce(0, +)
return total - sum
}
print(findMissing([1, 2, 4, 5, 6])) // 3
// Using XOR
func findMissingXOR(_ arr: [Int]) -> Int {
let n = arr.count + 1
var xorSum = 0
for i in 1...n {
xorSum ^= i
}
for num in arr {
xorSum ^= num
}
return xorSum
}
print(findMissingXOR([1, 2, 4, 5, 6])) // 3Find duplicates using Set or filter.
- Set: Track seen elements
- Filter:
arr.filter { !seen.insert($0).inserted } - Dictionary: Count occurrences
- Complexity: O(n) time
// Find duplicates in Swift
func findDuplicates<T: Hashable>(_ arr: [T]) -> [T] {
var seen = Set<T>()
var duplicates = Set<T>()
for item in arr {
if seen.contains(item) {
duplicates.insert(item)
} else {
seen.insert(item)
}
}
return Array(duplicates)
}
print(findDuplicates([1, 2, 3, 2, 4, 3])) // [2, 3]
// Using filter
func findDuplicatesFilter<T: Hashable>(_ arr: [T]) -> [T] {
var seen = Set<T>()
return arr.filter { !seen.insert($0).inserted }
}
print(findDuplicatesFilter([1, 2, 3, 2, 4, 3])) // [2, 3]
// Using Dictionary
func findDuplicatesDict<T: Hashable>(_ arr: [T]) -> [T] {
var counts: [T: Int] = [:]
for item in arr {
counts[item, default: 0] += 1
}
return counts.filter { $0.value > 1 }.map { $0.key }
}Calculate sum using reduce or manual iteration.
- reduce:
arr.reduce(0, +) - Manual: Iterate and accumulate
- forEach:
arr.forEach { total += $0 } - Complexity: O(n) time
// Sum of array in Swift
func sumArray(_ arr: [Int]) -> Int {
return arr.reduce(0, +)
}
print(sumArray([1, 2, 3, 4, 5])) // 15
// Manual implementation
func sumArrayManual(_ arr: [Int]) -> Int {
var total = 0
for num in arr {
total += num
}
return total
}
print(sumArrayManual([1, 2, 3, 4, 5])) // 15
// Using forEach
func sumArrayForEach(_ arr: [Int]) -> Int {
var total = 0
arr.forEach { total += $0 }
return total
}Calculate average using sum divided by count.
- Method:
Double(sum) / Double(arr.count) - Empty array: Return 0
- Precision: Returns Double
- Manual: Iterate and calculate
// Average of array in Swift
func averageArray(_ arr: [Int]) -> Double {
guard !arr.isEmpty else { return 0 }
return Double(arr.reduce(0, +)) / Double(arr.count)
}
print(averageArray([1, 2, 3, 4, 5])) // 3.0
// Manual implementation
func averageArrayManual(_ arr: [Int]) -> Double {
guard !arr.isEmpty else { return 0 }
var total = 0
for num in arr {
total += num
}
return Double(total) / Double(arr.count)
}
print(averageArrayManual([1, 2, 3, 4, 5])) // 3.0
// Using floating point
func averageArrayFloat(_ arr: [Double]) -> Double {
guard !arr.isEmpty else { return 0 }
return arr.reduce(0, +) / Double(arr.count)
}Sort using sorted() or sort().
- Non-mutating:
arr.sorted() - Mutating:
arr.sort() - Custom:
sorted { $0 < $1 } - Complexity: O(n log n)
// Sort array ascending in Swift
func sortAscending(_ arr: [Int]) -> [Int] {
return arr.sorted()
}
print(sortAscending([5, 2, 8, 1, 9])) // [1, 2, 5, 8, 9]
// In-place sorting
func sortAscendingInPlace(_ arr: inout [Int]) {
arr.sort()
}
var numbers = [5, 2, 8, 1, 9]
sortAscendingInPlace(&numbers)
print(numbers) // [1, 2, 5, 8, 9]
// Using sorted with closure
func sortAscendingClosure(_ arr: [Int]) -> [Int] {
return arr.sorted { $0 < $1 }
}Sort descending using sorted(by: >) or sort(by: >).
- Non-mutating:
arr.sorted(by: >) - Mutating:
arr.sort(by: >) - Custom:
sorted { $0 > $1 } - Complexity: O(n log n)
// Sort array descending in Swift
func sortDescending(_ arr: [Int]) -> [Int] {
return arr.sorted(by: >)
}
print(sortDescending([5, 2, 8, 1, 9])) // [9, 8, 5, 2, 1]
// In-place sorting
func sortDescendingInPlace(_ arr: inout [Int]) {
arr.sort(by: >)
}
var numbers = [5, 2, 8, 1, 9]
sortDescendingInPlace(&numbers)
print(numbers) // [9, 8, 5, 2, 1]
// Using sorted with closure
func sortDescendingClosure(_ arr: [Int]) -> [Int] {
return arr.sorted { $0 > $1 }
}Flatten using recursion or flatMap.
- Recursive: Check if element is array
- flatMap:
arr.flatMap { $0 }(for 2D) - Reduce:
reduce(into: []) - Complexity: O(n) time
// Flatten nested array in Swift
func flattenArray<T>(_ arr: [Any]) -> [T] {
var result: [T] = []
for item in arr {
if let nested = item as? [Any] {
result += flattenArray(nested)
} else if let value = item as? T {
result.append(value)
}
}
return result
}
let nested = [1, [2, [3, 4], 5], 6] as [Any]
let flattened: [Int] = flattenArray(nested)
print(flattened) // [1, 2, 3, 4, 5, 6]
// Using flatMap (for 2D only)
func flatten2D<T>(_ arr: [[T]]) -> [T] {
return arr.flatMap { $0 }
}
let nested2D = [[1, 2], [3, 4], [5, 6]]
print(flatten2D(nested2D)) // [1, 2, 3, 4, 5, 6]
// Using reduce
func flattenReduce<T>(_ arr: [Any]) -> [T] {
return arr.reduce(into: []) { result, item in
if let nested = item as? [Any] {
result += flattenReduce(nested) as [T]
} else if let value = item as? T {
result.append(value)
}
}
}Split array into chunks using stride or manual slicing.
- stride:
stride(from: 0, to: arr.count, by: size) - Slice:
arr[$0..<min($0 + size, arr.count)] - Edge case: Handle last chunk
- Complexity: O(n) time
// Chunk array in Swift
func chunkArray<T>(_ arr: [T], size: Int) -> [[T]] {
return stride(from: 0, to: arr.count, by: size).map {
Array(arr[$0..<min($0 + size, arr.count)])
}
}
print(chunkArray([1, 2, 3, 4, 5, 6], size: 2)) // [[1, 2], [3, 4], [5, 6]]
// Using while loop
func chunkArrayWhile<T>(_ arr: [T], size: Int) -> [[T]] {
var result: [[T]] = []
var i = 0
while i < arr.count {
let end = min(i + size, arr.count)
result.append(Array(arr[i..<end]))
i += size
}
return result
}
print(chunkArrayWhile([1, 2, 3, 4, 5, 6], size: 2))
// With padding
func chunkArrayPadding<T>(_ arr: [T], size: Int, padValue: T) -> [[T]] {
var chunks = chunkArray(arr, size: size)
if let last = chunks.last, last.count < size {
var padded = last
while padded.count < size {
padded.append(padValue)
}
chunks[chunks.count - 1] = padded
}
return chunks
}
print(chunkArrayPadding([1, 2, 3, 4, 5], size: 3, padValue: 0))Binary search using while loop or recursion.
- Iterative: While loop with left/right pointers
- Recursive: Recursive function call
- Requirement: Array must be sorted
- Complexity: O(log n) time
// Binary search in Swift
func binarySearch(_ arr: [Int], target: Int) -> Int? {
var left = 0
var right = arr.count - 1
while left <= right {
let mid = (left + right) / 2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return nil
}
print(binarySearch([1, 2, 3, 4, 5, 6, 7], target: 5) ?? -1) // 4
// Recursive binary search
func binarySearchRecursive(_ arr: [Int], target: Int, left: Int, right: Int) -> Int? {
if left > right {
return nil
}
let mid = (left + right) / 2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
return binarySearchRecursive(arr, target: target, left: mid + 1, right: right)
} else {
return binarySearchRecursive(arr, target: target, left: left, right: mid - 1)
}
}
print(binarySearchRecursive([1, 2, 3, 4, 5, 6, 7], target: 5, left: 0, right: 6) ?? -1)Quick sort using recursion and partitioning.
- Algorithm: Choose pivot, partition, recurse
- Time: O(n log n) average
- In-place: Implement for performance
- Pivot: First element or random
// Quick sort in Swift
func quickSort(_ arr: [Int]) -> [Int] {
if arr.count <= 1 {
return arr
}
let pivot = arr[0]
let left = arr.filter { $0 < pivot }
let right = arr.filter { $0 > pivot }
return quickSort(left) + [pivot] + quickSort(right)
}
print(quickSort([5, 3, 8, 4, 2, 7, 1, 6]))
// In-place quick sort
func quickSortInPlace(_ arr: inout [Int], low: Int, high: Int) {
if low < high {
let pi = partition(&arr, low: low, high: high)
quickSortInPlace(&arr, low: low, high: pi - 1)
quickSortInPlace(&arr, low: pi + 1, high: high)
}
}
func partition(_ arr: inout [Int], low: Int, high: Int) -> Int {
let pivot = arr[high]
var i = low - 1
for j in low..<high {
if arr[j] <= pivot {
i += 1
arr.swapAt(i, j)
}
}
arr.swapAt(i + 1, high)
return i + 1
}
var numbers = [5, 3, 8, 4, 2, 7, 1, 6]
quickSortInPlace(&numbers, low: 0, high: numbers.count - 1)
print(numbers)Merge sort using divide-and-conquer and merging.
- Algorithm: Divide, sort, merge
- Time: O(n log n)
- Stable: Maintains relative order
- Space: O(n) auxiliary space
// Merge sort in Swift
func mergeSort(_ arr: [Int]) -> [Int] {
if arr.count <= 1 {
return arr
}
let mid = arr.count / 2
let left = mergeSort(Array(arr[0..<mid]))
let right = mergeSort(Array(arr[mid..<arr.count]))
return merge(left, right)
}
func merge(_ left: [Int], _ right: [Int]) -> [Int] {
var result: [Int] = []
var i = 0, j = 0
while i < left.count && j < right.count {
if left[i] <= right[j] {
result.append(left[i])
i += 1
} else {
result.append(right[j])
j += 1
}
}
result.append(contentsOf: left[i...])
result.append(contentsOf: right[j...])
return result
}
print(mergeSort([5, 3, 8, 4, 2, 7, 1, 6]))Bubble sort with early termination optimization.
- Algorithm: Compare adjacent, swap
- Time: O(n²) worst case
- Optimization: Stop if no swaps
- In-place: Modifies original array
// Bubble sort in Swift
func bubbleSort(_ arr: [Int]) -> [Int] {
var sorted = arr
for i in 0..<sorted.count - 1 {
for j in 0..<sorted.count - 1 - i {
if sorted[j] > sorted[j + 1] {
sorted.swapAt(j, j + 1)
}
}
}
return sorted
}
print(bubbleSort([5, 3, 8, 4, 2, 7, 1, 6]))
// Optimized bubble sort
func bubbleSortOptimized(_ arr: [Int]) -> [Int] {
var sorted = arr
for i in 0..<sorted.count - 1 {
var swapped = false
for j in 0..<sorted.count - 1 - i {
if sorted[j] > sorted[j + 1] {
sorted.swapAt(j, j + 1)
swapped = true
}
}
if !swapped {
break
}
}
return sorted
}
print(bubbleSortOptimized([5, 3, 8, 4, 2, 7, 1, 6]))Find common elements using Set or filter.
- Set:
Array(Set(arr1).intersection(Set(arr2))) - Filter:
arr1.filter { arr2.contains($0) } - Complexity: O(n) time with Set
- Return: Array of common elements
// Intersection of arrays in Swift
func intersection<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
let set2 = Set(arr2)
return arr1.filter { set2.contains($0) }
}
print(intersection([1, 2, 3, 4], [3, 4, 5, 6])) // [3, 4]
// Using Set
func intersectionSet<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
let set1 = Set(arr1)
let set2 = Set(arr2)
return Array(set1.intersection(set2))
}
print(intersectionSet([1, 2, 3, 4], [3, 4, 5, 6])) // [3, 4]
// Using filter
func intersectionFilter<T: Equatable>(_ arr1: [T], _ arr2: [T]) -> [T] {
return arr1.filter { arr2.contains($0) }
}Combine arrays with unique elements using Set.
- Set:
Array(Set(arr1).union(Set(arr2))) - Preserve order: Use filter with Set
- Complexity: O(n) time
- Return: Array of unique elements
// Union of arrays in Swift
func union<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
return Array(Set(arr1).union(Set(arr2)))
}
print(union([1, 2, 3], [3, 4, 5])) // [1, 2, 3, 4, 5]
// Preserving order
func unionOrder<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
var result = arr1
for item in arr2 where !result.contains(item) {
result.append(item)
}
return result
}
print(unionOrder([1, 2, 3], [3, 4, 5])) // [1, 2, 3, 4, 5]
// Using reduce
func unionReduce<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
return arr1 + arr2.filter { !arr1.contains($0) }
}Find elements in first array not in second using Set.
- Set:
Array(Set(arr1).subtracting(Set(arr2))) - Filter:
arr1.filter { !arr2.contains($0) } - Symmetric difference:
symmetricDifference - Complexity: O(n) time
// Difference of arrays in Swift
func difference<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
let set2 = Set(arr2)
return arr1.filter { !set2.contains($0) }
}
print(difference([1, 2, 3, 4], [3, 4, 5, 6])) // [1, 2]
// Symmetric difference
func symmetricDifference<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> [T] {
let set1 = Set(arr1)
let set2 = Set(arr2)
return Array(set1.symmetricDifference(set2))
}
print(symmetricDifference([1, 2, 3], [3, 4, 5])) // [1, 2, 4, 5]
// Using filter
func differenceFilter<T: Equatable>(_ arr1: [T], _ arr2: [T]) -> [T] {
return arr1.filter { !arr2.contains($0) }
}Group objects by property using Dictionary(grouping:).
- Dictionary:
Dictionary(grouping: items, by: { $0.type }) - KeyPath: Use KeyPath for grouping
- Complexity: O(n) time
- Return: Dictionary with grouped items
// Group by property in Swift
struct Item {
let type: String
let name: String
}
func groupByProperty(_ items: [Item], keyPath: KeyPath<Item, String>) -> [String: [Item]] {
return Dictionary(grouping: items, by: { $0[keyPath: keyPath] })
}
// Usage
let data = [
Item(type: "fruit", name: "apple"),
Item(type: "fruit", name: "banana"),
Item(type: "veg", name: "carrot")
]
let groups = groupByProperty(data, keyPath: .type)
for (key, items) in groups {
print("\(key): \(items.map { $0.name })")
}
// Using Dictionary grouping
func groupByType(_ items: [Item]) -> [String: [Item]] {
return Dictionary(grouping: items) { $0.type }
}
print(groupByType(data))
// Group with count
func groupByPropertyCount(_ items: [Item], keyPath: KeyPath<Item, String>) -> [String: Int] {
let groups = Dictionary(grouping: items, by: { $0[keyPath: keyPath] })
return groups.mapValues { $0.count }
}
print(groupByPropertyCount(data, keyPath: .type))Deep clone using Codable or manual copy.
- Codable:
JSONDecoder().decode(T.self, from: JSONEncoder().encode(obj)) - Manual: Recursive copy
- NSCopying: Implement copy protocol
- Benefits: Complete independent copy
// Deep clone in Swift
struct Address {
var city: String
var zip: String
}
struct User {
var name: String
var address: Address
}
func deepClone<T: Codable>(_ obj: T) throws -> T {
let encoder = JSONEncoder()
let data = try encoder.encode(obj)
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
}
// Manual deep clone
func manualDeepClone(_ user: User) -> User {
return User(
name: user.name,
address: Address(city: user.address.city, zip: user.address.zip)
)
}
// Usage
let original = User(
name: "Alice",
address: Address(city: "NYC", zip: "10001")
)
let cloned = manualDeepClone(original)
var clonedMutable = cloned
clonedMutable.name = "Bob"
clonedMutable.address.city = "LA"
print("Original: \(original)")
print("Cloned: \(clonedMutable)")Perform immutable updates using struct copy or with function.
- Struct copy: Copy and modify
- with:
with(state) { $0.user.age = 26 } - KeyPath: Update using KeyPath
- Return: New immutable object
// Immutable update in Swift
struct User {
var name: String
var age: Int
}
struct State {
var user: User
}
func updateImmutable(_ state: State, keyPath: WritableKeyPath<State, Int>, value: Int) -> State {
var newState = state
newState[keyPath: keyPath] = value
return newState
}
// Usage
let state = State(user: User(name: "Alice", age: 25))
let newState = updateImmutable(state, keyPath: .user.age, value: 26)
print("Original: \(state.user.age)")
print("New: \(newState.user.age)")
// Using with function
func with<T>(_ obj: T, update: (inout T) -> Void) -> T {
var mutable = obj
update(&mutable)
return mutable
}
let state2 = with(state) { $0.user.age = 27 }
print("With: \(state2.user.age)")Pipe composes functions from left to right.
- Implementation:
transforms.reduce(value) { $1($0) } - Operator: Custom
|>operator - Return: Function that chains operations
- Direction: Left to right
// Pipe function in Swift
func pipe<T>(_ value: T, _ transforms: [(T) -> T]) -> T {
return transforms.reduce(value) { $1($0) }
}
func pipe<T, U, V>(_ f: @escaping (T) -> U, _ g: @escaping (U) -> V) -> (T) -> V {
return { g(f($0)) }
}
// Usage
let double = { (x: Int) -> Int in x * 2 }
let addTen = { (x: Int) -> Int in x + 10 }
let square = { (x: Int) -> Int in x * x }
let process = pipe(double, addTen, square)
let result = process(5)
print(result) // (5*2+10)^2 = 400
// Using array of transforms
let transforms: [(Int) -> Int] = [double, addTen, square]
let result2 = pipe(5, transforms)
print(result2) // 400
// Custom pipe operator
infix operator |> : AdditionPrecedence
func |> <T, U>(value: T, transform: (T) -> U) -> U {
return transform(value)
}
let result3 = 5 |> double |> addTen |> square
print(result3) // 400Compose functions from right to left.
- Implementation:
transforms.reversed().reduce(value) { $1($0) } - Operator: Custom
>>>operator - Return: Function that chains operations
- Direction: Right to left
// Compose function in Swift
func compose<T, U, V>(_ f: @escaping (U) -> V, _ g: @escaping (T) -> U) -> (T) -> V {
return { f(g($0)) }
}
// Usage
let double = { (x: Int) -> Int in x * 2 }
let addTen = { (x: Int) -> Int in x + 10 }
let square = { (x: Int) -> Int in x * x }
let squareThenAddTen = compose(addTen, square)
let result = squareThenAddTen(5)
print(result) // (5^2 + 10) = 35
// Variadic compose
func composeVariadic<T>(_ transforms: [(T) -> T]) -> (T) -> T {
return { value in
transforms.reversed().reduce(value) { $1($0) }
}
}
let process = composeVariadic([double, addTen, square])
let result2 = process(5)
print(result2) // (5*2+10)^2 = 400
// Custom compose operator
infix operator >>> : AdditionPrecedence
func >>> <T, U, V>(f: @escaping (U) -> V, g: @escaping (T) -> U) -> (T) -> V {
return { f(g($0)) }
}
let process3 = addTen >>> double >>> square
let result3 = process3(5)
print(result3) // (5*2+10)^2 = 400Cache function results based on arguments using dictionary.
- Cache:
[T: U] - Key: Function arguments
- Return: Cached or computed result
- Trade-off: Memory for speed
// Memoization in Swift
func memoize<T: Hashable, U>(_ function: @escaping (T) -> U) -> (T) -> U {
var cache: [T: U] = [:]
return { input in
if let cached = cache[input] {
return cached
}
let result = function(input)
cache[input] = result
return result
}
}
// Fibonacci with memoization
let fibMemo = memoize { (n: Int) -> Int in
if n <= 1 {
return n
}
return fibMemo(n - 1) + fibMemo(n - 2)
}
print(fibMemo(10)) // 55
// Memoize with class
class Memoizer<T: Hashable, U> {
private var cache: [T: U] = [:]
private let function: (T) -> U
init(function: @escaping (T) -> U) {
self.function = function
}
func call(_ input: T) -> U {
if let cached = cache[input] {
return cached
}
let result = function(input)
cache[input] = result
return result
}
}
let fibMemoizer = Memoizer { (n: Int) -> Int in
if n <= 1 {
return n
}
return fibMemoizer.call(n - 1) + fibMemoizer.call(n - 2)
}
print(fibMemoizer.call(10)) // 55Ensure a function is called only once using closure.
- Closure:
var called = false - Result: Cache the result
- Return: Function with guard
- Use case: Initialization
// Once function in Swift
func once<T>(_ function: @autoclosure @escaping () -> T) -> () -> T {
var called = false
var result: T?
return {
if !called {
called = true
result = function()
}
return result!
}
}
// Usage
let initialize = once {
print("Initialized")
return 42
}
print(initialize()) // Prints "Initialized", returns 42
print(initialize()) // Returns 42 (cached)
// Once with class
class Once<T> {
private var called = false
private var result: T?
private let function: () -> T
init(function: @escaping () -> T) {
self.function = function
}
func call() -> T {
if !called {
called = true
result = function()
}
return result!
}
}
let onceInstance = Once {
print("Initialized 2")
return "Hello"
}
print(onceInstance.call()) // Prints "Initialized 2"
print(onceInstance.call()) // Returns cachedDebounce with leading edge using timer and timestamp.
- Timer:
Timerfor delayed execution - Leading edge: Execute immediately
- Cooldown: Wait before next execution
- Use case: Search input, API calls
// Debounce with leading edge in Swift
import Foundation
func debounceLeading<T>(delay: TimeInterval, action: @escaping (T) -> Void) -> (T) -> Void {
var lastCall: Date = Date()
var timer: Timer?
return { input in
let now = Date()
if now.timeIntervalSince(lastCall) < delay {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { _ in
lastCall = Date()
action(input)
}
} else {
lastCall = now
action(input)
}
}
}
// Usage
let debounced = debounceLeading(delay: 1.0) { value in
print("Executed: \(value)")
}
debounced("First") // Executes immediately
debounced("Second") // Scheduled for later
debounced("Third") // Scheduled for later
// Keep main thread alive
RunLoop.current.run(until: Date().addingTimeInterval(2))Throttle with leading edge using timestamp tracking.
- Timestamp: Track last execution time
- Leading edge: Execute if enough time passed
- Rate limiting: At most once per period
- Use case: Scroll events, resize
// Throttle with leading edge in Swift
import Foundation
func throttleLeading<T>(delay: TimeInterval, action: @escaping (T) -> Void) -> (T) -> Void {
var lastCall: Date = Date()
return { input in
let now = Date()
if now.timeIntervalSince(lastCall) >= delay {
lastCall = now
action(input)
}
}
}
// Usage
let throttled = throttleLeading(delay: 1.0) { value in
print("Executed: \(value)")
}
throttled("First") // Executes
throttled("Second") // Ignored (within 1 second)
throttled("Third") // Ignored (within 1 second)
// Keep main thread alive
RunLoop.current.run(until: Date().addingTimeInterval(2))Deep equality comparison using Equatable protocol.
- Equatable:
extension User: Equatable - Manual: Recursive comparison
- Arrays: Compare elements recursively
- Objects: Compare fields recursively
// Deep equal in Swift
func deepEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
return a == b
}
// For custom structs, conform to Equatable
struct Address: Equatable {
let city: String
let zip: String
}
struct User: Equatable {
let name: String
let address: Address
}
// Usage
let user1 = User(name: "Alice", address: Address(city: "NYC", zip: "10001"))
let user2 = User(name: "Alice", address: Address(city: "NYC", zip: "10001"))
let user3 = User(name: "Bob", address: Address(city: "LA", zip: "90001"))
print(deepEqual(user1, user2)) // true
print(deepEqual(user1, user3)) // false
// Manual deep equal for arrays
func deepEqualArray<T: Equatable>(_ a: [T], _ b: [T]) -> Bool {
guard a.count == b.count else { return false }
for (item1, item2) in zip(a, b) {
if item1 != item2 {
return false
}
}
return true
}
let arr1 = [1, 2, 3]
let arr2 = [1, 2, 3]
let arr3 = [1, 2, 4]
print(deepEqualArray(arr1, arr2)) // true
print(deepEqualArray(arr1, arr3)) // falseObservable pattern with subscribers and notifications.
- Observable: Maintains subscribers
- Subscribe: Add callback
- Notify: Call all subscribers
- Unsubscribe: Remove callback
// Observable pattern in Swift
class Observable<T> {
private var observers: [(T) -> Void] = []
private var value: T
init(_ value: T) {
self.value = value
}
func subscribe(_ observer: @escaping (T) -> Void) -> () -> Void {
observers.append(observer)
observer(value) // Immediately notify with current value
return {
self.observers.removeAll { $0 as AnyObject === observer as AnyObject }
}
}
func update(_ newValue: T) {
value = newValue
observers.forEach { $0(newValue) }
}
}
// Usage
let observable = Observable("Hello")
let unsubscribe = observable.subscribe { value in
print("Observer received: \(value)")
}
observable.update("World") // Prints "Observer received: World"
unsubscribe()
observable.update("Again") // Nothing happens
// Multiple observers
let observable2 = Observable(0)
observable2.subscribe { value in
print("Observer 1: \(value)")
}
observable2.subscribe { value in
print("Observer 2: \(value)")
}
observable2.update(42)Singleton pattern using static constant.
- Static constant:
static let shared = Singleton() - Private init:
private init() - Lazy initialization:
static var shared: Singleton = () - Global access:
Singleton.shared
// Singleton pattern in Swift
class Singleton {
static let shared = Singleton()
private init() {} // Private initializer
private var data: [String: Any] = [:]
func set(_ key: String, value: Any) {
data[key] = value
}
func get(_ key: String) -> Any? {
return data[key]
}
}
// Usage
let singleton1 = Singleton.shared
let singleton2 = Singleton.shared
singleton1.set("name", value: "Alice")
print(singleton2.get("name") ?? "nil") // Alice
print(singleton1 === singleton2) // true
// Singleton with lazy initialization
class LazySingleton {
static var shared: LazySingleton = {
let instance = LazySingleton()
// Additional setup
return instance
}()
private init() {}
}
// Singleton with dispatch_once (using static)
class DatabaseSingleton {
static let shared = DatabaseSingleton()
private init() {
print("Database initialized")
}
}Factory pattern using static methods.
- Factory method:
static func create(type: String) -> User - Type parameter: Determines which class
- Return: Instance of requested type
- Benefits: Decouples creation logic
// Factory pattern in Swift
protocol User {
var name: String { get }
func getRole() -> String
}
struct Admin: User {
let name: String
func getRole() -> String { return "admin" }
}
struct Guest: User {
let name: String
func getRole() -> String { return "guest" }
}
struct RegularUser: User {
let name: String
func getRole() -> String { return "regular" }
}
class UserFactory {
static func createUser(type: String, name: String) -> User {
switch type {
case "admin":
return Admin(name: name)
case "guest":
return Guest(name: name)
default:
return RegularUser(name: name)
}
}
}
// Usage
let admin = UserFactory.createUser(type: "admin", name: "Alice")
let guest = UserFactory.createUser(type: "guest", name: "Bob")
print("\(admin.name) role: \(admin.getRole())")
print("\(guest.name) role: \(guest.getRole())")
// Abstract factory
protocol Widget {
func draw()
}
struct Button: Widget {
func draw() { print("Drawing Button") }
}
struct TextField: Widget {
func draw() { print("Drawing TextField") }
}
class WidgetFactory {
static func createWidget(type: String) -> Widget? {
switch type {
case "button":
return Button()
case "textfield":
return TextField()
default:
return nil
}
}
}
let button = WidgetFactory.createWidget(type: "button")
button?.draw()Strategy pattern using protocols.
- Strategy protocol: Define algorithm interface
- Concrete strategies: Implement protocol
- Context: Uses strategy
- Runtime switching: Change strategy at runtime
// Strategy pattern in Swift
protocol PaymentStrategy {
func pay(amount: Double)
}
struct CreditCardStrategy: PaymentStrategy {
func pay(amount: Double) {
print("Paid $\(amount) with Credit Card")
}
}
struct PayPalStrategy: PaymentStrategy {
func pay(amount: Double) {
print("Paid $\(amount) with PayPal")
}
}
struct CryptoStrategy: PaymentStrategy {
func pay(amount: Double) {
print("Paid $\(amount) with Crypto")
}
}
class PaymentContext {
private var strategy: PaymentStrategy
init(strategy: PaymentStrategy) {
self.strategy = strategy
}
func setStrategy(_ strategy: PaymentStrategy) {
self.strategy = strategy
}
func executePayment(amount: Double) {
strategy.pay(amount: amount)
}
}
// Usage
let context = PaymentContext(strategy: CreditCardStrategy())
context.executePayment(amount: 100.0)
context.setStrategy(PayPalStrategy())
context.executePayment(amount: 50.0)
context.setStrategy(CryptoStrategy())
context.executePayment(amount: 75.0)
// Strategy with closures
typealias PaymentClosure = (Double) -> Void
let creditCardPayment: PaymentClosure = { amount in
print("Paid $\(amount) with Credit Card")
}
let payPalPayment: PaymentClosure = { amount in
print("Paid $\(amount) with PayPal")
}
creditCardPayment(100)
payPalPayment(50)Observer pattern with subject and observers.
- Subject: Maintains observers
- Observer protocol: Defines update method
- Attach/Detach: Add/remove observers
- Notify: Call update on all observers
// Observer pattern in Swift
protocol Observer: AnyObject {
func update(data: String)
}
class Subject {
private var observers: [Observer] = []
private(set) var state: String = "" {
didSet {
notifyObservers()
}
}
func attach(_ observer: Observer) {
observers.append(observer)
}
func detach(_ observer: Observer) {
observers.removeAll { $0 === observer }
}
func setState(_ state: String) {
self.state = state
}
private func notifyObservers() {
observers.forEach { $0.update(data: state) }
}
}
class ConcreteObserver: Observer {
let name: String
init(name: String) {
self.name = name
}
func update(data: String) {
print("\(name) received: \(data)")
}
}
// Usage
let subject = Subject()
let observer1 = ConcreteObserver(name: "Observer1")
let observer2 = ConcreteObserver(name: "Observer2")
subject.attach(observer1)
subject.attach(observer2)
subject.setState("Hello World")
subject.detach(observer1)
subject.setState("Hello again")
// Using closures for observer
class ClosureSubject {
private var observers: [(String) -> Void] = []
private(set) var state: String = "" {
didSet {
observers.forEach { $0(state) }
}
}
func subscribe(_ observer: @escaping (String) -> Void) -> () -> Void {
observers.append(observer)
return {
self.observers.removeAll { $0 as AnyObject === observer as AnyObject }
}
}
func setState(_ state: String) {
self.state = state
}
}
let closureSubject = ClosureSubject()
let unsubscribe = closureSubject.subscribe { data in
print("Closure observer received: \(data)")
}
closureSubject.setState("Hello Closure")
unsubscribe()
closureSubject.setState("Again")Decorator pattern using wrapper structs.
- Component: Base object
- Decorator: Wraps component
- Chaining: Multiple decorators
- Benefits: Add behavior dynamically
// Decorator pattern in Swift
protocol Coffee {
var cost: Double { get }
var description: String { get }
}
struct SimpleCoffee: Coffee {
let cost: Double = 5.0
let description: String = "Coffee"
}
struct MilkDecorator: Coffee {
let coffee: Coffee
var cost: Double {
return coffee.cost + 2.0
}
var description: String {
return "\(coffee.description), Milk"
}
}
struct SugarDecorator: Coffee {
let coffee: Coffee
var cost: Double {
return coffee.cost + 1.0
}
var description: String {
return "\(coffee.description), Sugar"
}
}
struct WhippedCreamDecorator: Coffee {
let coffee: Coffee
var cost: Double {
return coffee.cost + 1.5
}
var description: String {
return "\(coffee.description), Whipped Cream"
}
}
// Usage
var coffee: Coffee = SimpleCoffee()
coffee = MilkDecorator(coffee: coffee)
coffee = SugarDecorator(coffee: coffee)
coffee = WhippedCreamDecorator(coffee: coffee)
print(coffee.description) // Coffee, Milk, Sugar, Whipped Cream
print(coffee.cost) // 9.5
// Using function decorators
func milkDecorator(_ coffee: Coffee) -> Coffee {
return MilkDecorator(coffee: coffee)
}
func sugarDecorator(_ coffee: Coffee) -> Coffee {
return SugarDecorator(coffee: coffee)
}
var coffee2: Coffee = SimpleCoffee()
coffee2 = milkDecorator(coffee2)
coffee2 = sugarDecorator(coffee2)
print(coffee2.description) // Coffee, Milk, SugarCommand pattern with execute and undo methods.
- Command protocol: Execute and undo
- Receiver: Performs actual work
- Invoker: Executes commands
- Undo/Redo: Command history
// Command pattern in Swift
protocol Command {
func execute()
func undo()
}
class AddCommand: Command {
private var receiver: [Int]
private let value: Int
init(receiver: inout [Int], value: Int) {
self.receiver = receiver
self.value = value
}
func execute() {
receiver.append(value)
}
func undo() {
if let index = receiver.firstIndex(of: value) {
receiver.remove(at: index)
}
}
}
// Command manager for undo/redo
class CommandManager {
private var history: [Command] = []
private var redoStack: [Command] = []
func execute(_ command: Command) {
command.execute()
history.append(command)
redoStack.removeAll()
}
func undo() {
guard let command = history.last else { return }
command.undo()
history.removeLast()
redoStack.append(command)
}
func redo() {
guard let command = redoStack.last else { return }
command.execute()
redoStack.removeLast()
history.append(command)
}
}
// Usage
var receiver = [1, 2, 3]
let manager = CommandManager()
let addCommand = AddCommand(receiver: &receiver, value: 4)
manager.execute(addCommand)
print(receiver) // [1, 2, 3, 4]
manager.undo()
print(receiver) // [1, 2, 3]
manager.redo()
print(receiver) // [1, 2, 3, 4]Memento pattern for state capture and restoration.
- Originator: Creates and restores mementos
- Memento: Stores state
- Caretaker: Manages mementos
- Undo/Redo: State history
// Memento pattern in Swift
class Memento {
let state: String
init(state: String) {
self.state = state
}
}
class Originator {
var state: String = ""
func saveState() -> Memento {
return Memento(state: state)
}
func restoreState(_ memento: Memento) {
state = memento.state
}
}
class Caretaker {
private var mementos: [Memento] = []
func addMemento(_ memento: Memento) {
mementos.append(memento)
}
func getMemento(at index: Int) -> Memento? {
guard index < mementos.count else { return nil }
return mementos[index]
}
}
// Usage
let originator = Originator()
let caretaker = Caretaker()
originator.state = "State 1"
caretaker.addMemento(originator.saveState())
originator.state = "State 2"
caretaker.addMemento(originator.saveState())
originator.state = "State 3"
if let memento = caretaker.getMemento(at: 0) {
originator.restoreState(memento)
print("Restored: \(originator.state)") // State 1
}
// Memento with Codable
struct CodableMemento<T: Codable>: Codable {
let state: T
}
class CodableOriginator<T: Codable> {
var state: T
init(state: T) {
self.state = state
}
func saveState() -> CodableMemento<T> {
return CodableMemento(state: state)
}
func restoreState(_ memento: CodableMemento<T>) {
state = memento.state
}
}Mediator pattern for centralized communication.
- Mediator: Encapsulates communication
- Colleague: Communicates through mediator
- Benefits: Loose coupling
- Use case: Chat systems
// Mediator pattern in Swift
class Mediator {
private var colleagues: [Colleague] = []
func register(_ colleague: Colleague) {
colleagues.append(colleague)
colleague.mediator = self
}
func send(message: String, from sender: Colleague) {
colleagues.forEach { colleague in
if colleague !== sender {
colleague.receive(message: message)
}
}
}
}
class Colleague {
let name: String
weak var mediator: Mediator?
init(name: String) {
self.name = name
}
func send(message: String) {
mediator?.send(message: message, from: self)
}
func receive(message: String) {
print("\(name) received: \(message)")
}
}
// Usage
let mediator = Mediator()
let alice = Colleague(name: "Alice")
let bob = Colleague(name: "Bob")
mediator.register(alice)
mediator.register(bob)
alice.send(message: "Hello Bob!")
// Chat room mediator
class ChatRoom: Mediator {
private var history: [String] = []
override func send(message: String, from sender: Colleague) {
history.append("\(sender.name): \(message)")
super.send(message: message, from: sender)
}
func getHistory() -> [String] {
return history
}
}
let chatRoom = ChatRoom()
let user1 = Colleague(name: "User1")
let user2 = Colleague(name: "User2")
chatRoom.register(user1)
chatRoom.register(user2)
user1.send(message: "Hello everyone!")
print(chatRoom.getHistory())Chain of Responsibility using protocols.
- Handler: Processes or forwards
- Chain: Linked list of handlers
- Benefits: Decoupling
- Use case: Logging, authentication
// Chain of Responsibility in Swift
protocol Handler {
var nextHandler: Handler? { get set }
func handle(request: [String: Any])
}
extension Handler {
mutating func setNext(_ handler: Handler) -> Handler {
self.nextHandler = handler
return handler
}
}
class AuthHandler: Handler {
var nextHandler: Handler?
func handle(request: [String: Any]) {
if let _ = request["token"] {
print("Authentication passed")
nextHandler?.handle(request: request)
} else {
print("Authentication failed")
}
}
}
class LoggerHandler: Handler {
var nextHandler: Handler?
func handle(request: [String: Any]) {
print("Logging request: \(request["url"] ?? "unknown")")
nextHandler?.handle(request: request)
}
}
class PermissionHandler: Handler {
var nextHandler: Handler?
func handle(request: [String: Any]) {
if let permissions = request["permissions"] as? [String],
permissions.contains("read") {
print("Permission granted")
nextHandler?.handle(request: request)
} else {
print("Permission denied")
}
}
}
// Usage
var auth = AuthHandler()
var logger = LoggerHandler()
var permission = PermissionHandler()
auth.nextHandler = logger
logger.nextHandler = permission
auth.handle(request: [
"token": "valid",
"url": "/api/data",
"permissions": ["read"]
])State pattern for changing behavior with state.
- Context: Maintains state
- State: Defines behavior
- Transitions: Change between states
- Benefits: Clean state management
// State pattern in Swift
protocol State {
func handle(context: Context)
}
class ReadyState: State {
func handle(context: Context) {
print("Ready: Waiting for input")
context.state = ProcessingState()
}
}
class ProcessingState: State {
func handle(context: Context) {
print("Processing: Working on task")
context.state = CompletedState()
}
}
class CompletedState: State {
func handle(context: Context) {
print("Completed: Task finished")
}
}
class Context {
var state: State = ReadyState()
func request() {
state.handle(context: self)
}
}
// Usage
let context = Context()
context.request() // Ready: Waiting for input
context.request() // Processing: Working on task
context.request() // Completed: Task finished
// Order state with transitions
class OrderState {
enum State {
case pending, processing, shipped, delivered, cancelled
}
private(set) var currentState: State = .pending
let transitions: [State: [State]] = [
.pending: [.processing, .cancelled],
.processing: [.shipped, .cancelled],
.shipped: [.delivered, .returned],
.delivered: [.returned]
]
func transition(to newState: State) -> Bool {
guard let allowed = transitions[currentState],
allowed.contains(newState) else {
print("Invalid transition from \(currentState) to \(newState)")
return false
}
currentState = newState
print("Order status changed to: \(newState)")
return true
}
}
let order = OrderState()
order.transition(to: .processing)
order.transition(to: .shipped)
order.transition(to: .delivered)Proxy pattern for controlling access.
- Subject: Real object
- Proxy: Controls access
- Lazy loading: Create on demand
- Benefits: Access control, logging
// Proxy pattern in Swift
protocol Subject {
func request()
}
class RealSubject: Subject {
func request() {
print("RealSubject: Handling request")
}
}
class Proxy: Subject {
private var realSubject: RealSubject?
func request() {
if checkAccess() {
if realSubject == nil {
realSubject = RealSubject()
}
realSubject?.request()
logAccess()
}
}
private func checkAccess() -> Bool {
print("Proxy: Checking access")
return true
}
private func logAccess() {
print("Proxy: Logging access")
}
}
// Usage
let proxy = Proxy()
proxy.request()
// Virtual proxy (lazy loading)
class VirtualProxy: Subject {
private var realSubject: RealSubject?
func request() {
if realSubject == nil {
print("Proxy: Creating real subject")
realSubject = RealSubject()
}
realSubject?.request()
}
}
let virtualProxy = VirtualProxy()
virtualProxy.request() // Creates real subject
virtualProxy.request() // Uses existing subject
// Protection proxy
class ProtectionProxy: Subject {
private var realSubject: RealSubject?
private let user: String
init(user: String) {
self.user = user
}
func request() {
if user == "admin" {
if realSubject == nil {
realSubject = RealSubject()
}
realSubject?.request()
} else {
print("Proxy: Access denied for user \(user)")
}
}
}
let protectedProxy = ProtectionProxy(user: "guest")
protectedProxy.request()Flyweight pattern for sharing objects.
- Flyweight: Shared object
- Factory: Manages flyweights
- Benefits: Memory optimization
- Use case: Character rendering
// Flyweight pattern in Swift
class Flyweight {
let sharedState: String
init(sharedState: String) {
self.sharedState = sharedState
}
func operation(uniqueState: String) {
print("Shared: \(sharedState), Unique: \(uniqueState)")
}
}
class FlyweightFactory {
private var flyweights: [String: Flyweight] = [:]
func getFlyweight(sharedState: String) -> Flyweight {
if let flyweight = flyweights[sharedState] {
return flyweight
}
let flyweight = Flyweight(sharedState: sharedState)
flyweights[sharedState] = flyweight
print("Creating new flyweight for: \(sharedState)")
return flyweight
}
}
// Usage
let factory = FlyweightFactory()
let fw1 = factory.getFlyweight(sharedState: "state1")
let fw2 = factory.getFlyweight(sharedState: "state1")
let fw3 = factory.getFlyweight(sharedState: "state2")
fw1.operation(uniqueState: "unique1")
fw2.operation(uniqueState: "unique2")
fw3.operation(uniqueState: "unique3")
// Character flyweight for text rendering
class Character {
let char: String
init(char: String) {
self.char = char
}
func display(fontSize: Int) {
print("Character: \(char), Size: \(fontSize)")
}
}
class CharacterFactory {
private var characters: [String: Character] = [:]
func getCharacter(_ char: String) -> Character {
if let character = characters[char] {
return character
}
let character = Character(char: char)
characters[char] = character
return character
}
}
let charFactory = CharacterFactory()
let text = "hello"
for char in text {
let character = charFactory.getCharacter(String(char))
character.display(fontSize: 12)
}Bridge pattern for separating abstraction from implementation.
- Abstraction: High-level interface
- Implementation: Low-level operations
- Benefits: Separation of concerns
- Use case: Cross-platform
// Bridge pattern in Swift
protocol Implementation {
func operationImpl()
}
struct ConcreteImplementationA: Implementation {
func operationImpl() {
print("ConcreteImplementationA: Operation")
}
}
struct ConcreteImplementationB: Implementation {
func operationImpl() {
print("ConcreteImplementationB: Operation")
}
}
class Abstraction {
private let impl: Implementation
init(impl: Implementation) {
self.impl = impl
}
func operation() {
print("Abstraction: Additional logic")
impl.operationImpl()
}
}
// Usage
let implA = ConcreteImplementationA()
let implB = ConcreteImplementationB()
let abstraction1 = Abstraction(impl: implA)
let abstraction2 = Abstraction(impl: implB)
abstraction1.operation()
abstraction2.operation()
// Extended abstraction
class ExtendedAbstraction: Abstraction {
override func operation() {
print("ExtendedAbstraction: More logic")
super.operation()
}
}
let extended = ExtendedAbstraction(impl: implA)
extended.operation()Adapter pattern for converting interfaces.
- Target: Expected interface
- Adaptee: Existing interface
- Adapter: Bridges interfaces
- Benefits: Reusability
// Adapter pattern in Swift
protocol Target {
func request()
}
struct TargetImpl: Target {
func request() {
print("Target: Request")
}
}
struct Adaptee {
func specificRequest() {
print("Adaptee: Specific Request")
}
}
struct Adapter: Target {
private let adaptee: Adaptee
init(adaptee: Adaptee) {
self.adaptee = adaptee
}
func request() {
adaptee.specificRequest()
}
}
// Usage
let adaptee = Adaptee()
let adapter = Adapter(adaptee: adaptee)
adapter.request()
// Object adapter (using composition)
class ObjectAdapter: Target {
private let adaptee: Adaptee
init(adaptee: Adaptee) {
self.adaptee = adaptee
}
func request() {
adaptee.specificRequest()
}
}
// Adapter for incompatible interfaces
struct OldSystem {
func oldMethod() -> String {
return "Old system data"
}
}
struct NewSystem {
func newMethod() -> String {
return "New system data"
}
}
struct SystemAdapter {
private let system: Any
init(system: Any) {
self.system = system
}
func getData() -> String? {
if let old = system as? OldSystem {
return old.oldMethod()
} else if let new = system as? NewSystem {
return new.newMethod()
}
return nil
}
}
let oldSystem = OldSystem()
let adapter2 = SystemAdapter(system: oldSystem)
print(adapter2.getData() ?? "nil")Facade pattern for simplifying subsystems.
- Facade: Simplified interface
- Subsystem: Complex components
- Benefits: Simplified interface
- Use case: Library APIs
// Facade pattern in Swift
class SubsystemA {
func operationA() {
print("SubsystemA: Operation")
}
}
class SubsystemB {
func operationB() {
print("SubsystemB: Operation")
}
}
class SubsystemC {
func operationC() {
print("SubsystemC: Operation")
}
}
class Facade {
private let subsystemA = SubsystemA()
private let subsystemB = SubsystemB()
private let subsystemC = SubsystemC()
func operation() {
print("Facade: Complex operation")
subsystemA.operationA()
subsystemB.operationB()
subsystemC.operationC()
}
func simplifiedOperation() {
print("Facade: Simplified operation")
subsystemA.operationA()
}
}
// Usage
let facade = Facade()
facade.operation()
facade.simplifiedOperation()
// Database facade
class DatabaseFacade {
private var connection: String?
func connect() {
print("Connecting to database")
connection = "Connected"
}
func query(_ sql: String) -> String? {
guard connection != nil else { return nil }
print("Executing: \(sql)")
return "Query results"
}
func disconnect() {
print("Disconnecting")
connection = nil
}
}
let db = DatabaseFacade()
db.connect()
let result = db.query("SELECT * FROM users")
db.disconnect()Composite pattern for tree structures.
- Component: Interface for all
- Leaf: Individual object
- Composite: Container
- Benefits: Uniform interface
// Composite pattern in Swift
protocol Component {
func operation()
}
struct Leaf: Component {
let name: String
func operation() {
print("Leaf \(name): Operation")
}
}
class Composite: Component {
let name: String
private var children: [Component] = []
init(name: String) {
self.name = name
}
func add(_ component: Component) {
children.append(component)
}
func remove(_ component: Component) {
children.removeAll { $0 as AnyObject === component as AnyObject }
}
func operation() {
print("Composite \(name): Operation")
children.forEach { $0.operation() }
}
}
// Usage
let leaf1 = Leaf(name: "A")
let leaf2 = Leaf(name: "B")
let composite = Composite(name: "Root")
composite.add(leaf1)
composite.add(leaf2)
composite.operation()
// File system example
protocol FileSystemComponent {
func getSize() -> Int
func display(indent: String)
}
class File: FileSystemComponent {
let name: String
let size: Int
init(name: String, size: Int) {
self.name = name
self.size = size
}
func getSize() -> Int {
return size
}
func display(indent: String = "") {
print("\(indent)📄 \(name) (\(size) bytes)")
}
}
class Directory: FileSystemComponent {
let name: String
private var children: [FileSystemComponent] = []
init(name: String) {
self.name = name
}
func add(_ component: FileSystemComponent) {
children.append(component)
}
func getSize() -> Int {
return children.reduce(0) { $0 + $1.getSize() }
}
func display(indent: String = "") {
print("\(indent)📁 \(name) (\(getSize()) bytes)")
children.forEach { $0.display(indent: indent + " ") }
}
}
let root = Directory(name: "Root")
let file1 = File(name: "file1.txt", size: 100)
let file2 = File(name: "file2.txt", size: 200)
let subDir = Directory(name: "SubDir")
subDir.add(File(name: "file3.txt", size: 300))
root.add(file1)
root.add(file2)
root.add(subDir)
root.display()Visitor pattern for adding operations without modifying elements.
- Visitor: Defines operations
- Element: Accepts visitors
- Benefits: Adding operations without modifying
- Use case: Compilers, AST
// Visitor pattern in Swift
protocol Visitor {
func visit(elementA: ElementA)
func visit(elementB: ElementB)
}
protocol Element {
func accept(_ visitor: Visitor)
}
struct ElementA: Element {
let data: String
func accept(_ visitor: Visitor) {
visitor.visit(elementA: self)
}
}
struct ElementB: Element {
let data: String
func accept(_ visitor: Visitor) {
visitor.visit(elementB: self)
}
}
struct ConcreteVisitor: Visitor {
func visit(elementA: ElementA) {
print("Visiting ElementA with data: \(elementA.data)")
}
func visit(elementB: ElementB) {
print("Visiting ElementB with data: \(elementB.data)")
}
}
// Usage
let visitor = ConcreteVisitor()
let elementA = ElementA(data: "A data")
let elementB = ElementB(data: "B data")
elementA.accept(visitor)
elementB.accept(visitor)
// Visitor with multiple operations
protocol OperationVisitor {
func visit(elementA: ElementA) -> String
func visit(elementB: ElementB) -> String
}
struct PrintVisitor: OperationVisitor {
func visit(elementA: ElementA) -> String {
return "Print: ElementA - \(elementA.data)"
}
func visit(elementB: ElementB) -> String {
return "Print: ElementB - \(elementB.data)"
}
}
struct CountVisitor: OperationVisitor {
var count = 0
mutating func visit(elementA: ElementA) -> String {
count += 1
return "ElementA counted"
}
mutating func visit(elementB: ElementB) -> String {
count += 1
return "ElementB counted"
}
}
let elements: [Element] = [ElementA(data: "A1"), ElementB(data: "B1"), ElementA(data: "A2")]
var printVisitor = PrintVisitor()
var countVisitor = CountVisitor()
for element in elements {
if let a = element as? ElementA {
print(printVisitor.visit(elementA: a))
_ = countVisitor.visit(elementA: a)
} else if let b = element as? ElementB {
print(printVisitor.visit(elementB: b))
_ = countVisitor.visit(elementB: b)
}
}
print("Total elements: \(countVisitor.count)")Iterator pattern for sequential access.
- Iterator: Traverses collection
- Aggregate: Creates iterator
- Benefits: Uniform traversal
- Use case: Collection traversal
// Iterator pattern in Swift
struct CustomIterator<T>: IteratorProtocol {
private let collection: [T]
private var index = 0
init(collection: [T]) {
self.collection = collection
}
mutating func next() -> T? {
guard index < collection.count else { return nil }
let element = collection[index]
index += 1
return element
}
}
struct CustomCollection<T>: Sequence {
private let items: [T]
init(_ items: [T]) {
self.items = items
}
func makeIterator() -> CustomIterator<T> {
return CustomIterator(collection: items)
}
}
// Usage
let collection = CustomCollection(["A", "B", "C"])
for item in collection {
print(item)
}
// Fibonacci iterator
struct FibonacciIterator: IteratorProtocol {
var a = 0
var b = 1
mutating func next() -> Int? {
let value = a
let temp = a + b
a = b
b = temp
return value
}
}
struct FibonacciSequence: Sequence {
let count: Int
func makeIterator() -> FibonacciIterator {
return FibonacciIterator()
}
}
for num in FibonacciSequence(count: 10).prefix(10) {
print(num)
}
// Step iterator
struct StepIterator<T>: IteratorProtocol {
private let collection: [T]
private let step: Int
private var index = 0
init(collection: [T], step: Int) {
self.collection = collection
self.step = step
}
mutating func next() -> T? {
guard index < collection.count else { return nil }
let element = collection[index]
index += step
return element
}
}
let stepIterator = StepIterator(collection: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], step: 2)
while let value = stepIterator.next() {
print(value) // 1, 3, 5, 7, 9
}Template Method for algorithm skeletons.
- AbstractClass: Defines template
- ConcreteClass: Implements steps
- Benefits: Code reuse
- Use case: Frameworks
// Template Method pattern in Swift
class AbstractClass {
func templateMethod() {
step1()
step2()
step3()
}
func step1() {
print("Step 1")
}
func step2() {
// Abstract - to be overridden
}
func step3() {
print("Step 3")
}
}
class ConcreteClass: AbstractClass {
override func step2() {
print("Concrete Step 2")
}
}
// Usage
let concrete = ConcreteClass()
concrete.templateMethod()
// Data processor template
class DataProcessor {
func process(_ data: [String: Any]) {
validate(data)
transform(data)
save(data)
notify(data)
}
func validate(_ data: [String: Any]) {
if data.isEmpty {
print("Data is empty")
}
print("Data validated")
}
func transform(_ data: [String: Any]) {
// Abstract - to be overridden
}
func save(_ data: [String: Any]) {
print("Data saved: \(data)")
}
func notify(_ data: [String: Any]) {
print("Notification sent")
}
}
class JSONProcessor: DataProcessor {
override func transform(_ data: [String: Any]) {
print("Transforming JSON: \(data)")
}
}
class XMLProcessor: DataProcessor {
override func transform(_ data: [String: Any]) {
print("Transforming XML: \(data)")
}
}
let jsonProcessor = JSONProcessor()
jsonProcessor.process(["name": "Alice"])
let xmlProcessor = XMLProcessor()
xmlProcessor.process(["name": "Bob"])Builder pattern for constructing complex objects.
- Builder: Constructs parts
- Director: Orchestrates construction
- Product: Constructed object
- Benefits: Step-by-step construction
// Builder pattern in Swift
class Product {
private var parts: [String] = []
func add(_ part: String) {
parts.append(part)
}
func listParts() {
print(parts.joined(separator: ", "))
}
}
class Builder {
private var product = Product()
func reset() {
product = Product()
}
func buildStepA() {
product.add("Part A")
}
func buildStepB() {
product.add("Part B")
}
func getResult() -> Product {
return product
}
}
class Director {
private let builder: Builder
init(builder: Builder) {
self.builder = builder
}
func buildMinimal() {
builder.buildStepA()
}
func buildFull() {
builder.buildStepA()
builder.buildStepB()
}
}
// Usage
let builder = Builder()
let director = Director(builder: builder)
director.buildMinimal()
let product = builder.getResult()
product.listParts() // Part A
// Fluent builder
class FluentBuilder {
private var product: [String: Any] = [:]
func name(_ name: String) -> FluentBuilder {
product["name"] = name
return self
}
func age(_ age: Int) -> FluentBuilder {
product["age"] = age
return self
}
func email(_ email: String) -> FluentBuilder {
product["email"] = email
return self
}
func build() -> [String: Any] {
return product
}
}
let user = FluentBuilder()
.name("Alice")
.age(25)
.email("alice@example.com")
.build()
print(user)Prototype pattern for cloning objects.
- Prototype: Cloneable object
- Clone: Creates a copy
- Deep copy: Recursive copy
- Benefits: Object reuse, performance
// Prototype pattern in Swift
class Prototype: NSCopying {
var name: String
var nested: [String: Any]
init(name: String, nested: [String: Any]) {
self.name = name
self.nested = nested
}
func copy(with zone: NSZone? = nil) -> Any {
return Prototype(name: name, nested: nested)
}
func deepCopy() -> Prototype {
let nestedCopy = nested.mapValues { value in
if let dict = value as? [String: Any] {
return dict
} else if let array = value as? [Any] {
return array
}
return value
}
return Prototype(name: name, nested: nestedCopy)
}
}
// Usage
let original = Prototype(name: "Original", nested: ["value": 42])
let copy = original.copy() as! Prototype
copy.name = "Copy"
copy.nested["value"] = 99
print(original.name) // Original
print(original.nested["value"] ?? 0) // 42 (shallow copy)
let deepCopy = original.deepCopy()
deepCopy.nested["value"] = 100
print(original.nested["value"] ?? 0) // 42 (deep copy)
// Using Codable for deep copy
struct CodablePrototype: Codable {
var name: String
var nested: [String: Int]
func deepCopy() throws -> CodablePrototype {
let encoder = JSONEncoder()
let data = try encoder.encode(self)
let decoder = JSONDecoder()
return try decoder.decode(CodablePrototype.self, from: data)
}
}
let codableOriginal = CodablePrototype(name: "Original", nested: ["value": 42])
let codableCopy = try? codableOriginal.deepCopy()
codableCopy?.name = "Copy"
codableCopy?.nested["value"] = 99
print(codableOriginal.name) // OriginalError handling using Result type for success/failure.
- Result type:
Result<Success, Failure> - Success:
.success(value) - Failure:
.failure(error) - Switch: Handle both cases
// Error Handling with Result type
enum NetworkError: Error {
case invalidURL
case noData
case decodingError
}
func fetchUser(id: Int) -> Result<User, NetworkError> {
// Simulate API call
guard id > 0 else { return .failure(.invalidURL) }
// Simulate success
let user = User(id: id, name: "Alice", email: "alice@example.com")
return .success(user)
}
// Usage
let result = fetchUser(id: 1)
switch result {
case .success(let user):
print("User: \(user.name)")
case .failure(let error):
print("Error: \(error)")
}JSON serialization using Codable and JSONEncoder.
- Codable:
struct Person: Codable - Encoder:
JSONEncoder().encode(person) - Decoder:
JSONDecoder().decode(Person.self, from: data) - Error handling:
try-catch
// JSON Encoding and Decoding
struct Person: Codable {
let name: String
let age: Int
let email: String
}
func encodePerson(_ person: Person) -> String? {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(person) else { return nil }
return String(data: data, encoding: .utf8)
}
func decodePerson(_ json: String) -> Person? {
guard let data = json.data(using: .utf8) else { return nil }
let decoder = JSONDecoder()
return try? decoder.decode(Person.self, from: data)
}
// Usage
let person = Person(name: "Alice", age: 25, email: "alice@example.com")
let json = encodePerson(person)
print(json ?? "")
let decoded = decodePerson(json ?? "")
print(decoded ?? person)Concurrency using DispatchQueue for async tasks.
- Serial queue:
DispatchQueue(label: "serial") - Concurrent queue:
.attributes: .concurrent - Main queue:
DispatchQueue.main.async - Barrier:
.async(flags: .barrier)
// Concurrency with DispatchQueue
import Foundation
// Serial queue
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
print("Task 1")
Thread.sleep(forTimeInterval: 0.5)
}
serialQueue.async {
print("Task 2")
}
// Concurrent queue
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
concurrentQueue.async {
print("Concurrent Task 1")
Thread.sleep(forTimeInterval: 0.5)
}
concurrentQueue.async {
print("Concurrent Task 2")
}
// Main queue
DispatchQueue.main.async {
print("Main queue task")
}
// Barrier
concurrentQueue.async(flags: .barrier) {
print("Barrier task")
}Asynchronous programming using async/await and Task.
- async functions:
func fetch() async -> String - await:
let result = await fetch() - Task:
Task { } - Parallel:
async let
// Async/Await with Task
import Foundation
func fetchUser(id: Int) async throws -> User {
try await Task.sleep(nanoseconds: 1_000_000_000)
return User(id: id, name: "Alice", email: "alice@example.com")
}
func fetchPosts(userId: Int) async throws -> [String] {
try await Task.sleep(nanoseconds: 500_000_000)
return ["Post 1", "Post 2"]
}
func fetchUserData() async {
do {
async let user = fetchUser(id: 1)
async let posts = fetchPosts(userId: 1)
let (userData, userPosts) = try await (user, posts)
print("User: \(userData.name)")
print("Posts: \(userPosts)")
} catch {
print("Error: \(error)")
}
}
Task {
await fetchUserData()
}Unit testing using XCTest framework.
- Test class:
class MyTests: XCTestCase - setUp/tearDown: Setup and cleanup
- Assertions:
XCTAssertEqual,XCTAssertThrowsError - Async tests:
func testAsync() async
// Testing with XCTest
import XCTest
class CalculatorTests: XCTestCase {
var calculator: Calculator!
override func setUp() {
super.setUp()
calculator = Calculator()
}
override func tearDown() {
calculator = nil
super.tearDown()
}
func testAdd() {
XCTAssertEqual(calculator.add(2, 3), 5)
XCTAssertEqual(calculator.add(-1, 1), 0)
}
func testDivide() {
XCTAssertEqual(try? calculator.divide(10, 2), 5)
XCTAssertThrowsError(try calculator.divide(10, 0))
}
func testAsyncOperation() async {
let result = await calculator.asyncAdd(2, 3)
XCTAssertEqual(result, 5)
}
}
class Calculator {
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
func divide(_ a: Int, _ b: Int) throws -> Int {
guard b != 0 else {
throw NSError(domain: "DivideError", code: 1)
}
return a / b
}
func asyncAdd(_ a: Int, _ b: Int) async -> Int {
try? await Task.sleep(nanoseconds: 100_000_000)
return a + b
}
}Closures with capture lists for memory management.
- Capture list:
[weak self] - Unowned:
[unowned self] - Escaping:
@escaping - Memory: Avoid retain cycles
// Closures and Capture Lists
class NetworkManager {
var data: String?
func fetchData(completion: @escaping () -> Void) {
DispatchQueue.global().async { [weak self] in
Thread.sleep(forTimeInterval: 0.5)
self?.data = "Data loaded"
DispatchQueue.main.async {
completion()
}
}
}
// Unowned capture
func processData() {
fetchData { [unowned self] in
print(self.data ?? "nil")
}
}
}
// Usage
let manager = NetworkManager()
manager.processData()
// Closure with capture list
var counter = 0
let increment = { [counter] in
print(counter) // Captures value at creation
}
counter = 10
increment() // Prints 0Property wrappers for reusable property logic.
- Definition:
@propertyWrapper struct Capitalized - wrappedValue:
var wrappedValue: Type - Usage:
@Capitalized var name: String - Parameters:
init(wrappedValue: Type, ...)
// Property Wrappers
@propertyWrapper
struct Capitalized {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
}
@propertyWrapper
struct MinMax {
private var value: Int
let min: Int
let max: Int
init(wrappedValue: Int, min: Int, max: Int) {
self.min = min
self.max = max
self.value = min(max(wrappedValue, min), max)
}
var wrappedValue: Int {
get { value }
set { value = min(max(newValue, min), max) }
}
}
struct User {
@Capitalized var name: String
@MinMax(min: 0, max: 150) var age: Int
}
var user = User(name: "alice", age: 25)
print(user.name) // Alice
user.age = 200
print(user.age) // 150Result builders for declarative DSL construction.
- @resultBuilder: Define builder
- buildBlock: Combine components
- buildEither: Conditional components
- Usage:
@ArrayBuilder
// Result Builders
@resultBuilder
struct ArrayBuilder<T> {
static func buildBlock(_ components: T...) -> [T] {
return components
}
}
func buildArray<T>(@ArrayBuilder<T> _ content: () -> [T]) -> [T] {
return content()
}
// Usage
let numbers = buildArray {
1
2
3
4
5
}
print(numbers) // [1, 2, 3, 4, 5]
// Conditional items
@resultBuilder
struct ConditionalBuilder<T> {
static func buildBlock(_ components: T...) -> [T] {
return components
}
static func buildEither(first: T) -> T {
return first
}
static func buildEither(second: T) -> T {
return second
}
}
func buildConditional<T>(_ condition: Bool, @ConditionalBuilder<T> _ content: () -> T) -> T {
return content()
}
let value = buildConditional(true) {
"Hello"
}
print(value) // HelloAsync sequences for streaming asynchronous data.
- AsyncSequence:
protocol AsyncSequence - AsyncIterator:
mutating func next() async - AsyncStream:
AsyncStream { continuation in } - Iteration:
for await
// AsyncSequence and AsyncStream
import Foundation
struct NumberGenerator: AsyncSequence {
typealias Element = Int
let max: Int
func makeAsyncIterator() -> AsyncIterator {
return AsyncIterator(max: max)
}
struct AsyncIterator: AsyncIteratorProtocol {
var current = 0
let max: Int
mutating func next() async -> Int? {
current += 1
if current > max {
return nil
}
try? await Task.sleep(nanoseconds: 100_000_000)
return current
}
}
}
// Usage
Task {
for await num in NumberGenerator(max: 5) {
print(num)
}
}
// AsyncStream
func createAsyncStream() -> AsyncStream<String> {
return AsyncStream { continuation in
Task {
for i in 1...5 {
try? await Task.sleep(nanoseconds: 100_000_000)
continuation.yield("Item \(i)")
}
continuation.finish()
}
}
}
Task {
for await item in createAsyncStream() {
print(item)
}
}Best practices for writing clean, efficient Swift code.
- Guard: Early returns with guard
- Extensions: Organize code
- Type inference: Let Swift infer types
- Optionals: Use optional binding
- Enums: Use enums for states
// Swift Best Practices
// 1. Use guard for early returns
func processUser(_ user: User?) -> String {
guard let user = user else { return "No user" }
guard !user.name.isEmpty else { return "Empty name" }
return "Hello, \(user.name)"
}
// 2. Use extensions for organization
extension String {
func isValidEmail() -> Bool {
return contains("@") && contains(".")
}
}
// 3. Use type inference
let name = "Alice" // String inferred
let age = 25 // Int inferred
// 4. Use optionals appropriately
let optionalValue: String? = "Hello"
if let unwrapped = optionalValue {
print(unwrapped)
}
// 5. Use enums for states
enum ResultState {
case success(data: String)
case error(message: String)
case loading
}
// 6. Use protocols for abstraction
protocol DataService {
func fetchData() -> String
}
// 7. Use value types (structs) when possible
struct UserData {
let id: Int
let name: String
}
// 8. Use computed properties
struct Circle {
var radius: Double
var area: Double {
return Double.pi * radius * radius
}
}
// 9. Use lazy properties for expensive initialization
class DataManager {
lazy var expensiveData: String = {
// Expensive computation
return "Data"
}()
}
// 10. Use weak references to avoid retain cycles
class Parent {
weak var child: Child?
}
class Child {
var parent: Parent?
}