💡 Introduction — Why Swift?
Swift is a modern, statically typed language emphasizing safety, clarity, and performance. Although widely used for Apple platforms, its language features (optionals, value types, generics, protocol-oriented design) make it excellent for algorithmic work and DSA templates.
🛠️ Toolchain & Tooling
- swiftc — compiler:
swiftc main.swift -o prog. - swift — REPL / script runner:
swift file.swift. - Swift Package Manager (SPM) —
swift build,swift test. - Use Xcode for app dev; use SPM + VS Code or CLI for DSA/contest work.
🔤 Types & Type Inference
Swift is strongly typed with excellent inference — prefer explicit types for public APIs and ambiguous literals.
``` let a: Int = 10 let b = 20 // inferred Int let s = "hello" // String let f = 3.14 // Double by default let arr = [1,2,3] // [Int]
⭕ Optionals & Nil Safety
Optionals encode presence/absence: Int? holds value or nil. Use safe unwrapping.
```
var name: String? = nil
if let actual = name {
print(actual)
} else {
print("no name")
}
let forced = name! // avoid unless certain 🔁 Value vs Reference Types
Structs & enums are value types (copied); classes are reference types (shared). Prefer structs when possible.
```
struct Point { var x:Int; var y:Int }
var p1 = Point(x:1,y:2)
var p2 = p1
p2.x = 5 // p1.x still 1
class Node { var val:Int; init(_ v:Int){val=v} }
let n1 = Node(1); let n2 = n1
n2.val = 9 // n1.val is 9 🧠 Memory: ARC & Copy-On-Write (COW)
ARC manages class lifetimes. Collections are value types with COW — mutations trigger copies only when necessary.
Avoid strong reference cycles (use weak / unowned), and reserve capacity for large arrays.
🏗️ Structs, Classes & Enums
Swift enums are powerful ADTs with associated values; switch is exhaustive and safe.
``` enum Result{ case success(T) case failure(String) } struct User { let id:Int; var name:String } class Manager { var users:[User] = [] }
🔗 Protocols & Protocol-Oriented Design
Protocols + extensions enable powerful composition. Prefer small, focused protocols and default implementations via extensions.
```
protocol Describable { func describe() -> String }
extension Describable { func printIt(){ print(describe()) } }
struct Item: Describable {
let value:Int
func describe() -> String { "Item((value))" }
} ⚙️ Generics & Associated Types
Generics create reusable, type-safe containers. Use where for complex constraints.
``` struct Stack{ private var items = [T]() mutating func push(_ x:T){ items.append(x) } mutating func pop() -> T? { items.popLast() } }
🔁 Closures & Capture Lists
Closures capture variables; use capture lists ([weak self]) to avoid retain cycles when capturing self.
```
class C {
var handler: (() -> Void)?
func setHandler() {
handler = { [weak self] in
guard let s = self else { return }
print(s)
}
}
} 🛡️ Error Handling
Swift uses throwing functions and structured do/try/catch. Use typed errors and propagate with throws.
```
enum MyError: Error { case runtime(String) }
func mightFail(_ x:Int) throws -> Int {
if x == 0 { throw MyError.runtime("zero") }
return 10 / x
}
do {
let v = try mightFail(0)
print(v)
} catch { print("error:", error) } 📚 Collections & Algorithms
Arrays, Dictionary, Set are value types with many helpful standard methods. For long chains, consider LazySequence to avoid intermediates.
``` var arr = [5,2,9,1] arr.sort() // in-place let idx = arr.firstIndex(of: 9) let dict = ["a":1, "b":2] let set: Set = [1,2,3]
🎯 DSA Techniques in Swift
- Reserve capacity for arrays:
arr.reserveCapacity(n). - Prefer iterative solutions for deep inputs to avoid recursion limits.
- Implement heaps (array-based) for priority queues; stdlib doesn't include heap.
- Use
Dictionaryfor hash maps (average O(1)),Setfor membership. - Use
ContiguousArrayfor tighter memory layout when needed.
🧩 DSA Examples (Swift)
1. BFS (Adjacency List)
```
func bfs(adj: [[Int]], start: Int) -> [Int] {
var vis = Array(repeating:false, count: adj.count)
var q: [Int] = []
var res: [Int] = []
q.append(start); vis[start] = true
while !q.isEmpty {
let u = q.removeFirst()
res.append(u)
for v in adj[u] where !vis[v] {
vis[v] = true; q.append(v)
}
}
return res
}
```
2. Union-Find (DSU)
```
struct DSU {
private var parent: [Int]
private var rank: [Int]
init(_ n:Int) { parent = Array(0.. Int {
if parent[x] != x { parent[x] = find(parent[x]) }
return parent[x]
}
mutating func union(_ a:Int, _ b:Int) -> Bool {
var x = find(a), y = find(b)
if x == y { return false }
if rank[x] < rank[y] { swap(&x, &y) }
parent[y] = x
if rank[x] == rank[y] { rank[x] += 1 }
return true
}
}
```
3. Min-Heap (array-based)
```
struct MinHeap {
private var a: [Int] = []
mutating func push(_ x: Int) { a.append(x); siftUp(a.count-1) }
mutating func pop() -> Int? {
guard !a.isEmpty else { return nil }
a.swapAt(0, a.count-1); let v = a.removeLast()
siftDown(0); return v
}
private mutating func siftUp(_ i:Int) { var i=i; while i>0 {
let p=(i-1)/2; if a[p] <= a[i] { break }; a.swapAt(p,i); i=p } }
private mutating func siftDown(_ i:Int) { var i=i, n=a.count
while true {
let l=2*i+1, r=2*i+2; var smallest=i
if lCopy
```
4. Sliding Window Maximum
```
func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] {
guard k > 0, nums.count >= k else { return [] }
var dq: [Int] = [] // indices
var res: [Int] = []
for i in 0..= k - 1 { res.append(nums[dq.first!]) }
}
return res
} ✅ Best Practices & Common Pitfalls
- Prefer
letfor immutability; explicitvarfor mutability. - Avoid force-unwrapping optionals (
!); useguard letorif let. - Use
reserveCapacityto avoid repeated reallocations. - Avoid retain cycles with closures capturing
self— use[weak self]or[unowned self]. - Profile before micro-optimizing; use Instruments or simple timing for contest timings.
🏁 Final Summary — Swift Checklist
- Optionals & safe unwrapping
- Value types (structs) for safety & performance
- ARC & COW semantics — be mindful of references and copies
- Protocols & generics for reusable DSA code
- Preallocate, avoid unnecessary allocations in hot loops
Next: port your DSA templates to Swift, practice on contest platforms that accept Swift, and measure hotspots if performance matters.