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
224: Common Swift Interview Questions on Generics
I’ve sat through dozens of technical interviews, and there is one specific moment where I can tell a candidate understands Generics and where they are just guessing. It usually happens when I ask them to write a simple utility function to find a duplicate in an array. They'll start typing quickly, confident that T is just a placeholder for "whatever the user passes in," only to be stopped cold by a compiler error they didn't expect.
The Myth: "Generics are just a flexible version of Any"
The most common misconception I see is the belief that a generic type parameter (like T) behaves like Any. People think that because T can be anything, you can do anything to it. Let's look at why that's wrong. Consider this attempt at a function that checks if an array contains any duplicate elements:
func hasDuplicates<T>(items: [T]) -> Bool {
for (index, item) in items.enumerated() {
// This line will cause a compiler error!
if items[index + 1...] .contains(item) {
return true
}
}
return false
}
If you try to compile this, Swift will yell at you: Binary operator '==' cannot be applied to operands of type 'T' and 'T'. Why? Because to the compiler, T is a total mystery. It could be a String, an Int, or a CustomUserSession object that doesn't support equality checks. You can't use == or contains() because those require the type to be Equatable. Any allows you to store anything, but it strips away the type's identity; T preserves the identity, but it doesn't grant you powers the type doesn't actually have.
The Reality: Constraints are the Real Power
The key to passing the "Generics" portion of a Swift interview isn't knowing how to write <T>; it's knowing how to constrain it. When you tell Swift that T: Equatable, you aren't just adding a rule—you're unlocking a whole set of capabilities that the compiler now guarantees are safe.
Here is the corrected version of that duplicate check. Notice how the constraint changes everything:
func hasDuplicates<T: Equatable>(items: [T]) -> Bool {
for (index, item) in items.enumerated() {
if items[(index + 1)...].contains(item) {
return true
}
}
return false
}
I always tell my juniors: think of constraints as a contract. By saying T: Equatable, you're telling the compiler, "I don't care what this type is, as long as it knows how to compare itself to another instance of itself."
Handling Complex Requirements with the 'where' Clause
In more senior-level interviews, you'll likely be asked about scenarios where a simple T: Protocol isn't enough. For instance, what if you have a function that compares two different generic types, but only if they both share a common trait? This is where the where clause comes in.
Imagine you're building a system that compares two different types of "Version" objects (maybe a ServerVersion and a ClientVersion) to see if they are compatible. You can't just use T because the two inputs might be different types entirely.
func areCompatible<T, U>(versionA: T, versionB: U) -> Bool where T: Versionable, U: Versionable {
return versionA.majorVersion == versionB.majorVersion
}
The where clause allows you to define complex relationships. You can constrain the association between types, which is a huge step up from basic generic syntax. If you can demonstrate this in an interview, you're showing that you understand how to maintain type safety without sacrificing the flexibility of your API.
📋 Practical Task
Implementing a Type-Safe Generic Response Wrapper
In professional Swift development, we often wrap API responses in a generic Result-style object to handle success and failure consistently across different data models.
Your Task: Create a generic struct named NetworkResponse. It should have the following requirements:
- It must be generic over a type
T. - It should have a property
data: T?and a propertystatusCode: Int. - Implement a method called
isSuccessful() -> Boolthat returnstrueif thestatusCodeis in the range 200-299. - Implement a second method called
validateData() -> Bool. This method should only be available if the generic typeTconforms to theEquatableprotocol. It should take a parameterexpectedValue: Tand returntrueifdatamatches theexpectedValue.
Hint: You will need to use a where clause on the validateData method extension to ensure it only exists for Equatable types.
There are no comments for now.