Swift Dictionaries: Key-Value Storage Explained Clearly
Swift dictionaries let you store values by key instead of by numeric position. They are one of the most useful collection types in Swift because they make it easy to look up data quickly, group related information, and model real-world data such as usernames, scores, settings, product IDs, and more. In this guide, you will learn what Swift dictionaries are, how their syntax works, how to read and change values safely, and which mistakes beginners often make.
Quick answer: A Swift dictionary stores pairs of keys and values, written as [Key: Value]. You use a key to access its matching value, but dictionary lookups return an optional because the key may not exist.
Difficulty: Beginner
Helpful to know first: basic Swift syntax, how variables and constants work, and simple types like String, Int, and arrays.
1. What Is a Swift Dictionary?
A dictionary is a collection that stores data as key-value pairs. Each key must be unique, and each key maps to exactly one value.
- A dictionary uses keys instead of numeric indexes.
- The type is written as [Key: Value].
- Keys must be unique within the dictionary.
- Keys must conform to Hashable, which types like String, Int, and UUID already do.
- Looking up a key returns an optional value because the key may be missing.
If you need to store a list in order, an array is usually a better fit. If you need to look up data by a label or identifier, a dictionary is usually the right choice.
A common beginner comparison is Array vs Dictionary: arrays are for ordered collections accessed by index, while dictionaries are for keyed collections accessed by meaning.
2. Why Dictionaries Matter
Dictionaries are important because many real programs need fast lookups by some identifier rather than stepping through a list one element at a time.
You would commonly use a dictionary when:
- storing user preferences by setting name
- mapping employee IDs to employee names
- counting how many times words appear in text
- grouping product codes with prices
- tracking scores by player name
Without dictionaries, you would often need arrays of custom data and manual searching. That is slower to write, harder to read, and less efficient for simple key-based access.
You should not use a dictionary when the order of items is the main concern or when duplicate keys are required. In those situations, an array or another data structure may be a better choice.
3. Basic Syntax or Core Idea
Declaring a dictionary
Here is the simplest way to create a dictionary with explicit key and value types.
var scores: [String: Int] = [
"Alice": 95,
"Bob": 88
]This creates a mutable dictionary named scores where keys are String values and dictionary values are Int values.
Reading a value
When you read from a dictionary, Swift gives you an optional because the requested key might not exist.
let score = scores["Alice"]The result is an Int?, not a plain Int. That means you usually unwrap it with if let, nil coalescing, or another optional-handling technique.
Adding or updating a value
You can assign to a key to add a new entry or replace an existing one.
scores["Charlie"] = 91
scores["Alice"] = 97The first line adds a new key-value pair. The second line updates the existing value for Alice.
Removing a value
Setting a key to nil removes it from the dictionary.
scores["Bob"] = nilThis removes the key Bob and its value.
4. Step-by-Step Examples
Example 1: Creating a dictionary of country codes
This example shows a dictionary with string keys and string values.
let countryCodes: [String: String] = [
"US": "United States",
"FR": "France",
"JP": "Japan"
]This is a good use of a dictionary because each short code maps naturally to one full country name.
Example 2: Safely reading a value with optional binding
Because dictionary lookups can fail, optional binding is a safe way to read values.
if let country = countryCodes["FR"] {
print("Code FR means \(country)")
} else {
print("Code not found")
}This code handles both possibilities: the key exists or it does not.
Example 3: Counting words
Dictionaries are great for counting repeated values because the word becomes the key and the count becomes the value.
let words = ["apple", "banana", "apple", "orange", "banana", "apple"]
var counts: [String: Int] = [:]
for word in words {
counts[word, default: 0] += 1
}
print(counts)The default: value is very useful here. If the word is not already in the dictionary, Swift starts its count at 0.
Example 4: Looping through a dictionary
You can iterate through key-value pairs with a for-in loop.
let prices = [
"Notebook": 4.99,
"Pen": 1.49,
"Bag": 24.99
]
for (item, price) in prices {
print("\(item): $\(price)")
}This loops through every pair in the dictionary. The order is not something you should depend on.
Example 5: Starting with an empty dictionary
Sometimes you need to build a dictionary gradually.
var ages = [String: Int]()
ages["Mia"] = 29
ages["Leo"] = 34This creates an empty dictionary, then adds values one by one.
5. Practical Use Cases
- Store app settings where the setting name maps to a value.
- Look up a customer record by customer ID.
- Count tags, words, or categories in user-generated content.
- Map file extensions to MIME types or descriptions.
- Track game scores by player name.
- Build quick lookup tables for configuration or data normalization.
6. Common Mistakes
Mistake 1: Treating a dictionary lookup like a guaranteed value
Many beginners expect a dictionary lookup to return a normal value. In Swift, it returns an optional because the key may be missing.
Problem: This code tries to use a dictionary result as a non-optional Int, which causes a type mismatch or forces unsafe assumptions.
let scores = ["Alice": 95, "Bob": 88]
let aliceScore: Int = scores["Alice"]Fix: Unwrap the optional safely with if let or provide a fallback value with ??.
let scores = ["Alice": 95, "Bob": 88]
if let aliceScore = scores["Alice"] {
print("Alice scored \(aliceScore)")
}
let charlieScore = scores["Charlie"] ?? 0The corrected version works because it acknowledges that a dictionary key may or may not exist.
Mistake 2: Assuming dictionary order is fixed
Some beginners expect dictionaries to behave like arrays and always preserve a meaningful display order for program logic.
Problem: This code depends on the first element of a dictionary being a specific pair, but dictionary order should not be treated as a guaranteed business rule.
let scores = ["Alice": 95, "Bob": 88]
let firstPair = scores.first
print(firstPair!)Fix: If order matters, sort the dictionary entries or use an array for ordered data.
let scores = ["Alice": 95, "Bob": 88]
let sortedScores = scores.sorted { $0.key < $1.key }
for (name, score) in sortedScores {
print("\(name): \(score)")
}The corrected version works because it creates a predictable order before iterating.
Mistake 3: Trying to modify a dictionary stored in a constant
A dictionary declared with let cannot be changed after creation, even if the key and value types are mutable types themselves.
Problem: This code tries to add a new key to a constant dictionary, so Swift reports that the value is immutable.
let settings = ["theme": "dark"]
settings["language"] = "en"Fix: Declare the dictionary with var when you need to add, remove, or update entries.
var settings = ["theme": "dark"]
settings["language"] = "en"The corrected version works because a variable dictionary allows mutation.
Mistake 4: Forgetting that keys must be unique
A dictionary cannot store two separate values under the exact same key. Assigning the same key again replaces the old value.
Problem: This code assumes both values will be preserved, but the later assignment overwrites the earlier one.
var inventory: [String: Int] = [:]
inventory["Pen"] = 10
inventory["Pen"] = 25Fix: Use unique keys, or store an array as the value if one key needs multiple related items.
var inventoryByColor: [String: [Int]] = [:]
inventoryByColor["Pen"] = [10, 25]The corrected version works because the single key now maps to a value type that can hold multiple items.
7. Best Practices
Practice 1: Use meaningful key types
Keys should clearly represent how the data is looked up. A meaningful key type makes code easier to understand and reduces bugs.
// Less clear
var data: [String: String] = ["1": "Alice"]
// Clearer
var usernamesByID: [Int: String] = [1: "Alice"]The clearer version makes the relationship between the key and the value obvious.
Practice 2: Use the default-value subscript for counting and accumulation
When building counts or totals, the default: subscript keeps the code short and safe.
let letters = ["a", "b", "a", "c"]
var totals: [String: Int] = [:]
for letter in letters {
totals[letter, default: 0] += 1
}This avoids repetitive optional unwrapping when incrementing values.
Practice 3: Sort dictionary content only when presentation needs it
A dictionary is for lookup, not guaranteed display order. Sort the entries at the point where ordered output is needed.
let scores = ["Charlie": 91, "Alice": 95, "Bob": 88]
let sortedNames = scores.keys.sorted()
for name in sortedNames {
print("\(name): \(scores[name]!)")
}This keeps the dictionary focused on lookup while still allowing ordered output when needed.
Practice 4: Use updateValue(_:forKey:) when the old value matters
Subscript assignment is simple, but updateValue(_:forKey:) is helpful when you want the previous value back.
var scores = ["Alice": 95]
let oldValue = scores.updateValue(98, forKey: "Alice")
print(oldValue ?? 0)This is useful when updating data and logging or comparing the previous value.
8. Limitations and Edge Cases
- Dictionary lookups return optionals because missing keys are valid and expected.
- Keys must conform to Hashable. You cannot use arbitrary types as keys unless they support hashing.
- A dictionary cannot contain duplicate keys; later assignments replace earlier values.
- If output order matters, sort keys or entries before displaying them.
- An empty dictionary written as [:] may need explicit type information if Swift cannot infer the key and value types.
- Removing a value with dictionary[key] = nil deletes the entry instead of storing a normal value. This is important when working with optional value types.
- If your value type is itself optional, dictionary behavior can become harder to read, so many teams avoid optional values inside dictionaries unless truly necessary.
A common “why is this not working?” moment happens when Swift cannot infer the type of an empty dictionary. In that case, declare it explicitly, such as var scores: [String: Int] = [:].
9. Practical Mini Project
Let’s build a small program that tracks student grades. It will add students, update grades, print a report, and safely handle missing names.
var grades: [String: Int] = [
"Anna": 92,
"Ben": 85,
"Cara": 98
]
// Add a new student
grades["David"] = 90
// Update an existing grade
grades["Ben"] = 89
// Safely read one grade
if let annaGrade = grades["Anna"] {
print("Anna's grade is \(annaGrade)")
}
// Missing key with fallback
let evaGrade = grades["Eva"] ?? 0
print("Eva's grade is \(evaGrade)")
// Print a sorted report
for name in grades.keys.sorted() {
if let grade = grades[name] {
print("\(name): \(grade)")
}
}This mini project demonstrates the most common dictionary tasks: creating, adding, updating, reading safely, using a fallback value, and sorting for display.
10. Key Points
- A Swift dictionary stores key-value pairs using the type syntax [Key: Value].
- Keys must be unique and must conform to Hashable.
- Dictionary lookup returns an optional because the key might not exist.
- Assigning to a key adds a new value or replaces an existing one.
- Setting a key to nil removes it from the dictionary.
- Dictionaries are best for lookup by identifier, not for ordered lists.
- If you need predictable output order, sort the keys or entries before displaying them.
11. Practice Exercise
Create a Swift program that stores the stock count for three products in a dictionary.
- Add at least one new product after the dictionary is created.
- Update the stock count of an existing product.
- Print the stock count of one product using optional binding.
- Print a fallback value of 0 for a product that does not exist.
- Loop through the dictionary and print each product and count.
Expected output: The exact order may vary unless you sort the keys, but the program should print the updated stock information and show 0 for a missing product.
Hint: Use a dictionary like [String: Int], access values with dictionary[key], and use ?? for the missing product.
var stock: [String: Int] = [
"Laptop": 5,
"Mouse": 12,
"Keyboard": 7
]
// Add a new product
stock["Monitor"] = 4
// Update an existing product
stock["Mouse"] = 15
// Optional binding
if let keyboardCount = stock["Keyboard"] {
print("Keyboard stock: \(keyboardCount)")
}
// Fallback for missing key
let tabletCount = stock["Tablet"] ?? 0
print("Tablet stock: \(tabletCount)")
// Print all products in sorted order
for product in stock.keys.sorted() {
if let count = stock[product] {
print("\(product): \(count)")
}
}12. Final Summary
Swift dictionaries are one of the most practical collection types in the language. They let you connect a unique key to a value, which makes them ideal for quick lookups, counts, settings, IDs, and many other common tasks. Once you understand that dictionary lookups return optionals and that key order should not be relied on for logic, dictionaries become straightforward and powerful.
In this article, you learned how to create dictionaries, add and update entries, remove values, loop through key-value pairs, and avoid common beginner mistakes. A useful next step is to study Swift arrays and sets as well, so you can choose the right collection type for each problem.