Swift
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Optionals
-
Section 4: Object-Oriented and Value Types
-
Section 5: Memory Management
-
Section 6: Generics and Error Handling
-
Section 7: Concurrency
-
Section 8: Working with Collections
-
Section 9: Codable and Data Handling
-
Section 10: Protocol-Oriented Programming
-
Section 11: Testing and Tooling
-
Section 12: Practical Projects
-
Section 13: Interview Practice
-
Section 14: More Practice Exercises
-
Section 15: More Standard Library
-
Section 16: Advanced Concurrency
-
Section 17: Foundation Framework Deep Dive
-
Section 18: URLSession and Networking Deep Dive
-
Section 19: Combine Framework
-
Section 20: SwiftUI Fundamentals for Swift Developers
-
Section 21: Server-Side Swift with Vapor
-
Section 22: Swift Package Manager Deep Dive
-
Section 23: Swift Concurrency Deep Dive
-
Section 24: More Language Features
-
Section 25: Error Handling Deep Dive
-
Section 26: Testing Deep Dive
-
Section 27: Data Structures and Algorithms in Swift
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Swift Macros (Swift 5.9+)
-
Section 31: Property Wrappers Ecosystem
-
Section 32: Swift Interop Deep Dive
-
Section 33: iOS App Architecture Patterns
-
Section 34: Performance and Debugging
-
Section 35: App Distribution and CI/CD
-
Section 36: More Practical Projects
-
Section 37: SwiftData and Persistence
-
Section 38: More Design Patterns
-
Section 39: More Review and Practice
-
Section 40: More Foundation Deep Dive
-
Section 41: Advanced Collections in Swift
-
Section 42: Advanced Generics Practice
-
Section 43: UIKit for Legacy and Hybrid Apps
-
Section 44: watchOS and visionOS Development Basics
-
Section 45: More Networking Patterns
-
Section 46: More Testing Practice
-
Section 47: Accessibility in Swift Apps
-
Section 48: Localization
-
Section 49: More Practical Projects Round 2
-
Section 50: Swift Charts Framework
-
Section 51: More Interview and Algorithm Practice
-
Section 52: Final Practice and Mastery
-
Section 53: Swift Compiler and Build System
-
Section 54: More Concurrency Practice
-
Section 55: App Store Guidelines and Review
-
Section 56: More Design and Architecture
27: Generic Constraints
Up until now, we've treated generics as a way to make our code flexible. You've learned that T can be anything—an Int, a String, or some custom User struct. But here is the reality of professional development: "anything" is often too broad. If you try to actually do something with that generic type, you'll quickly run into a wall.
struct ScoreBoard<T> {
var scores: [T]
func findHighestScore() -> T? {
guard var highest = scores.first else { return nil }
for score in scores {
if score > highest { // ❌ ERROR HERE
highest = score
}
}
return highest
}
}
The "Binary Operator" Wall
If you try to compile the code above, Swift is going to yell at you with an error that looks something like: "Binary operator '>' cannot be applied to two 'T' operands."
I've seen a lot of learners get frustrated by this. You're thinking, "But I'm only going to use this with numbers! Why is the compiler complaining?" The problem is that the compiler doesn't know that. From Swift's perspective, T could be a UIImage or a NetworkRequest. You can't use the "greater than" operator on a image or a request. It doesn't make sense.
In Swift, the > and < operators aren't just magic; they are requirements of a specific protocol called Comparable. Since our T is currently "anything," it doesn't guaranteed that it conforms to Comparable.
Telling Swift what T can actually do
To fix this, we use a Generic Constraint. Instead of telling Swift that T can be any type, we tell it that T must be a type that conforms to Comparable. We do this by adding a colon after the type parameter.
struct ScoreBoard<T: Comparable> {
var scores: [T]
func findHighestScore() -> T? {
guard var highest = scores.first else { return nil }
for score in scores {
if score > highest { // ✅ This now works!
highest = score
}
}
return highest
}
}
By adding : Comparable, you've essentially created a contract. You're telling the compiler: "I don't care exactly what T is, as long as it knows how to compare itself to another instance of the same type." Now, the > operator is legal because the compiler knows every possible T that enters this struct will support it.
Handling Multiple Constraints with 'where'
Sometimes, one constraint isn't enough. Maybe you need your type to be Comparable so you can sort it, but you also need it to be Numeric so you can perform math on it. While you can comma-separate constraints in the angle brackets, it quickly becomes a mess to read.
This is where the where clause comes in. It's a much cleaner way to define complex requirements, especially when the constraint depends on a relationship between two different generic types.
func calculateAverage<T>(items: [T]) -> T where T: BinaryInteger {
let sum = items.reduce(0, +)
return sum / T(items.count)
}
I personally prefer the where clause for anything more complex than a single protocol. It keeps the function signature readable and separates the "what it is" (the type) from the "what it must do" (the constraint).
📋 Practical Task
Building a Generic Top-K Filter
Your task is to create a utility function that extracts the "Top K" elements from a collection. This is a common pattern in dashboards (e.g., "Top 5 High Scores" or "Top 3 Most Recent Posts").
Requirements:
- Create a function called
topElementsthat takes two arguments: an array of generic typeTand an integerk. - Use a generic constraint to ensure that
TisComparable. - The function should sort the array in descending order and return a new array containing only the first
kelements. - Ensure the function handles cases where
kis larger than the actual size of the array without crashing.
Test your code with:
let numbers = [12, 45, 2, 89, 34]
let top3Numbers = topElements(items: numbers, k: 3) // Should be [89, 45, 34]
let words = ["Apple", "Zebra", "Banana", "Mango"]
let top2Words = topElements(items: words, k: 2) // Should be ["Zebra", "Mango"]
There are no comments for now.