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
29: Result Type
Imagine you're ordering a pizza through an app. When you hit that "Order" button, you aren't getting the pizza immediately. Instead, you're entering a state of waiting for an outcome. That outcome is binary: either the delivery driver shows up at your door with a hot pepperoni pizza (Success), or you get a notification saying the shop is out of dough or your address was wrong (Failure).
Crucially, you can't have both. You don't get a half-delivered pizza and a "store closed" notification at the same time. It's one or the other.
In Swift, the Result type is exactly that: a way to wrap the outcome of an operation so that it's explicitly either a success with a value, or a failure with an error. It maps perfectly to our pizza analogy:
- The
Resulttype: The overall status of your order. .success(Value): The pizza arriving (the value is the actual pizza)..failure(Error): The notification explaining why you're still hungry (the value is the specific error).
Stop juggling double optionals
Before Result became the standard, we used to handle asynchronous callbacks by passing two optional arguments: (Data?, Error?). I've spent way too many hours debugging code where, due to a bug, both were nil or, somehow, both were populated. It was a mess because the compiler couldn't force you to handle the "impossible" states.
Result fixes this by using an enum. Since it's an enum, it's mathematically impossible to be in both states at once. Here is how I typically implement a network fetch using this pattern:
enum NetworkError: Error {
case badURL
case serverError
case decodingFailed
}
struct UserProfile {
let username: String
let bio: String
}
func fetchUserProfile(userId: String, completion: @escaping (Result<UserProfile, NetworkError>) -> Void) {
// Simulating a network call
let success = true
if success {
let user = UserProfile(username: "swift_dev", bio: "Coding the future.")
completion(.success(user))
} else {
completion(.failure(.serverError))
}
}
Handling the outcome with precision
The beauty of Result is that it forces you to acknowledge the failure path. I always use a switch statement to handle the response. It keeps the "happy path" and the "error path" visually separated, which makes the code much easier to scan during a code review.
fetchUserProfile(userId: "123") { result in
switch result {
case .success(let profile):
print("Welcome back, \(profile.username)!")
case .failure(let error):
switch error {
case .badURL:
print("Check your connection.")
case .serverError:
print("Our servers are acting up. Try again later.")
case .decodingFailed:
print("We got the data, but it looks weird.")
}
}
}
One little pro-tip: if you only care about the success value and want to ignore the error (though I'd advise against this in production), you can use try? result.get(). The get() method is a handy built-in that throws the error if the result is .failure or returns the value if it's .success.
📋 Practical Task
Implementing a Secure Vault Access Simulator
You need to build a system that simulates accessing a secure digital vault. The vault should only open if the provided passcode is correct. If the passcode is wrong, or if the vault is "locked for maintenance," it should return a specific error.
Your Task:
- Create an enum called
VaultErrorthat conforms toErrorwith two cases:invalidPasscodeandmaintenanceMode. - Create a function called
openVault(passcode: String)that returns aResult<String, VaultError>.- If the passcode is "1234", return
.successwith the string "Secret Documents Accessed". - If the passcode is "0000", return
.failure(.maintenanceMode). - For any other passcode, return
.failure(.invalidPasscode).
- If the passcode is "1234", return
- Call this function three times with different passcodes and use a
switchstatement to print a user-friendly message for every possible outcome (including the specific errors).
There are no comments for now.