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
53: Building a Small Data Model with Codable
Imagine you've just ordered a complex piece of furniture from IKEA. When the delivery truck arrives, you don't get a fully assembled bookshelf; you get a flat-pack box. Inside that box, everything is compressed, packed tightly, and described by a set of instructions. To actually use the bookshelf in your room, you have to "decode" those instructions and assemble the raw parts into a physical structure that makes sense in your environment.
In Swift, JSON is that flat-pack box. It's a great way to transport data over the internet because it's lightweight and text-based, but you can't really "do" much with a raw JSON string in your app logic. You need to turn that string into a Swift object—like a Struct—so you can access properties with dot notation and get the benefit of type safety. That's exactly what the Codable protocol does; it's the assembly manual that tells Swift how to map the raw data in the box to the actual object in your code.
Translating JSON into Swift Types
Let's say we're building a movie tracking app. The API sends us a movie object that looks like this:
{
"title": "Inception",
"release_year": 2010,
"is_classic": true
}
To handle this, we create a Struct that mirrors this shape. By conforming to Codable (which is actually just a shorthand for Encodable and Decodable), we tell Swift that this type is capable of being converted to and from a data format like JSON.
struct Movie: Codable {
let title: String
let releaseYear: Int
let isClassic: Bool
}
I'll let you in on a professional tip: always use let for your model properties unless you specifically know you'll be mutating them locally. Data coming from an API should generally be treated as immutable snapshots.
Handling the Naming Gap with CodingKeys
You probably noticed a problem in my example above. The JSON uses release_year (snake_case), but in Swift, we use releaseYear (camelCase). If the names don't match exactly, JSONDecoder will throw an error and your app will crash or fail to load the data. I've spent way too many hours debugging this exact mismatch in my early career.
We fix this using a special enum called CodingKeys. This acts as a translation map, telling Swift: "When you see release_year in the JSON, put it into the releaseYear property in my struct."
struct Movie: Codable {
let title: String
let releaseYear: Int
let isClassic: Bool
enum CodingKeys: String, CodingKey {
case title
case releaseYear = "release_year"
case isClassic = "is_classic"
}
}
Putting the Decoder to Work
Now that we have our model, we use JSONDecoder to actually perform the assembly. Here is how I usually set this up in a real project:
let jsonString = """
{
"title": "Inception",
"release_year": 2010,
"is_classic": true
}
"""
// Convert the string to Data, because JSONDecoder requires Data
if let jsonData = jsonString.data(using: .utf8) {
do {
let decoder = JSONDecoder()
let movie = try decoder.decode(Movie.self, from: jsonData)
print("Successfully decoded: \(movie.title) from \(movie.releaseYear)")
} catch {
print("Decoding failed: \(error)")
}
}
Notice the Movie.self part. We aren't passing an instance of a movie; we're passing the type itself, telling the decoder, "I want you to try and create something that fits the Movie blueprint."
📋 Practical Task
Build a Recipe Data Model for a Cooking App
You've been given a JSON snippet representing a cooking recipe. Your task is to create a Swift data model that can decode this JSON, handling the discrepancy between the JSON's snake_case and Swift's camelCase.
The JSON data:
{
"recipe_name": "Classic Margherita Pizza",
"prep_time_minutes": 15,
"is_vegetarian": true,
"calories": 800
}
Requirements:
- Create a struct named
Recipethat conforms toCodable. - Use camelCase for the property names (e.g.,
recipeNameinstead ofrecipe_name). - Implement
CodingKeysto map the JSON keys to your Swift properties. - Write the code to decode the JSON string into a
Recipeobject usingJSONDecoder. - Print the
recipeNameof the decoded object to the console to verify it works.
There are no comments for now.