Swift Sets
Add to favorites
From Basics to Advanced: Swift Set Techniques for Better Apps

SwiftUI Fundamentals Handbook
1
Building Your iOS Development Foundation
2
SwiftUI Print Debugging
18:04
3
Comments Documentation Waypoints
22:02
4
Variables and Constants
11:37
5
Strings and Interpolation
13:22
6
Swift Operators: The Foundation of SwiftUI Logic
5:34
7
Swift Unary Operators
15:00
8
Swift Binary Operators
3:36
9
Arithmetic Operators
6:11
10
If-Else and Comparison Operators
12:32
11
Logical Operators
6:03
12
Ternary Operators
13
Blocks and Scope
10:22
14
Swift Collections: Arrays, Sets, and Dictionaries Overview
15
Swift Arrays: The Basics Part 1
16
Swift Arrays: Best Practices in SwiftUI Part 2
17
Swift Sets
1. Introduction to Sets in Swift
Sets are one of the fundamental collection types in Swift, yet they're often overlooked in favor of arrays and dictionaries. Understanding sets—their unique properties, performance characteristics, and ideal use cases—can dramatically improve your SwiftUI applications. This introduction will explore what sets are, why they matter specifically in SwiftUI development, and how they compare to other collection types.
A. What Are Sets?
i. Definition and core characteristics
A set in Swift is an unordered collection of unique values. This seemingly simple definition carries powerful implications for how you structure and manipulate data in your applications. The key characteristics that define sets include:
- Uniqueness guarantee: Sets automatically ensure that each value appears only once—there can never be duplicates within a set. When you attempt to add a value that already exists, the set simply ignores the operation.
- Unordered collection: Unlike arrays, sets don't maintain any specific sequence of elements. You cannot access elements by index, and the order may change as you add or remove elements.
- Hashable requirement: All elements in a set must conform to the
Hashable
protocol. This requirement enables Swift to efficiently determine whether a value already exists in the set. - High-performance operations: Sets are optimized for testing whether a value exists, adding new unique values, and removing values, with these operations typically completing in constant time O(1) regardless of the set's size.
Sets exist to solve specific problems elegantly. When you work with collections where uniqueness matters more than order, or when you frequently need to check if a value exists in a collection, sets provide both conceptual clarity and performance benefits.
ii. The mental model: sets as mathematical collections
To understand sets in programming, it helps to connect them to their mathematical origins. In mathematics, a set is a collection of distinct objects considered as an object in its own right. The Swift implementation brings this mathematical construct into your code.
Think of a set as a bag where each distinct item can only appear once. You can add items to the bag or remove them, but you never need to worry about where in the bag a particular item resides—you only care whether it's in the bag or not.
This mental model reveals why sets excel at representing collections where membership is the primary concern: groups of unique identifiers, active filters in a filtering system, or categories that an item belongs to.
iii. Sets in Swift's type system
In Swift's type system, the Set
type is a generic collection defined as Set<Element>
, where Element
must conform to the Hashable
protocol. This protocol requirement enables the set to efficiently determine whether a value already exists.
Most of Swift's built-in types already conform to Hashable
, including strings, integers, floating-point numbers, and booleans. For custom types, you'll need to implement the Hashable
protocol, which we'll explore in a later section.
Sets are value types in Swift, meaning they're copied when assigned to a new variable or passed to a function. This behavior aligns with Swift's emphasis on value semantics, providing predictable and safe behavior in concurrent code.
B. Why Sets Matter in SwiftUI Development
Sets aren't just an abstract collection type—they solve real, practical problems in SwiftUI development that other collections can't address as elegantly.
i. Uniqueness in UI state management
SwiftUI's declarative approach to UI development is built around state management. Sets provide a natural way to manage states where uniqueness matters:
- Selection management: When users can select multiple items, a set naturally represents the selection state, ensuring each item can only be selected once.
struct ContentView: View {
// Using a Set to track selected item IDs ensures uniqueness
@State private var selectedItemIDs: Set<UUID> = []
let allItems: [Item]
var body: some View {
List(allItems) { item in
HStack {
Text(item.name)
Spacer()
if selectedItemIDs.contains(item.id) {
Image(systemName: "checkmark")
}
}
.contentShape(Rectangle())
.onTapGesture {
// If already selected, remove it; otherwise, add it
if selectedItemIDs.contains(item.id) {
selectedItemIDs.remove(item.id)
} else {
selectedItemIDs.insert(item.id)
}
}
}
}
}
- Filter state: When implementing filter systems (like in search interfaces), sets elegantly track which filters are currently active.
- Tab uniqueness: For custom tab systems where each tab should appear exactly once, sets provide a natural data structure.
ii. Performance benefits in reactive UI
SwiftUI rebuilds views when their state changes. Using the most efficient collection type can have substantial performance implications:
- Membership testing efficiency: When SwiftUI needs to check if an item is selected, favorited, or filtered, the
contains
operation on a set is dramatically faster than on an array, especially as the collection grows. - Change detection optimization: SwiftUI's performance depends on efficiently detecting what's changed. Sets help minimize unnecessary view updates by making it clear exactly what items are affected by a state change.
- Reduced view rebuilding: By using sets appropriately, you can minimize unnecessary view rebuilds by ensuring that state only changes when truly needed (no duplicates being added).
iii. Data integrity in SwiftUI applications
Sets help maintain data integrity within your SwiftUI applications:
- Preventing duplicate entries: In forms and data entry scenarios, sets ensure you don't accidentally store the same information twice.
- Enforcing business rules: Many business domains have inherent uniqueness requirements (like unique user IDs or exclusive options) that sets naturally enforce.
- State deduplication: When merging state from multiple sources (like local and remote data), sets automatically handle deduplication.
C. Sets vs Other Collection Types
Understanding how sets compare to arrays and dictionaries helps you choose the right collection for each situation in your SwiftUI applications.
i. Sets vs Arrays: choosing the right ordered or unordered collection
Arrays and sets serve different purposes and come with different tradeoffs:
Arrays:
- Preserve insertion order
- Allow duplicate elements
- Access elements by position/index
- Linear search performance O(n) for contains operations
- Better when sequence matters
Sets:
- Don't maintain any specific order
- Guarantee uniqueness (no duplicates)
- No direct positional access
- Constant time O(1) for contains operations
- Better when uniqueness and membership testing matter
Consider this performance comparison for checking if an element exists:
// With an array of 10,000 elements
let largeArray = Array(1...10000)
let startArray = Date()
let containsInArray = largeArray.contains(9876) // O(n) - might check thousands of elements
let arrayTime = Date().timeIntervalSince(startArray)
// With a set of the same elements
let largeSet = Set(1...10000)
let startSet = Date()
let containsInSet = largeSet.contains(9876) // O(1) - direct lookup
let setTime = Date().timeIntervalSince(startSet)
print("Array search took \(arrayTime) seconds")
print("Set search took \(setTime) seconds")
// Set search will typically be orders of magnitude faster
ii. Sets vs Dictionaries: when to use each associative collection
Sets and dictionaries are both associative collections, but they serve different needs:
Dictionaries:
- Store key-value pairs
- Each key maps to a specific value
- Used when you need to retrieve values associated with keys
- Keys must be hashable
Sets:
- Store single values, not pairs
- Used when you only care about whether a value exists, not what it maps to
- Elements must be hashable
Think of a set as similar to a dictionary where you only care about the keys, not the values. In fact, Swift's implementation of sets leverages the same hash table mechanism that powers dictionaries.
iii. Practical guidelines for collection selection in SwiftUI
When developing SwiftUI applications, consider these guidelines for choosing between collection types:
Choose an Array when:
- The order of elements matters (like items in a list that should maintain a specific sequence)
- You need to access elements by position (first, last, or nth element)
- Duplicate elements are valid and meaningful
- The collection is small, or you rarely need to search for specific elements
Choose a Set when:
- Uniqueness is required or beneficial
- You frequently check whether a value exists in the collection
- Order doesn't matter for how the data is used
- You need to perform mathematical set operations (union, intersection, etc.)
- Performance of membership testing is critical for your UI responsiveness
Choose a Dictionary when:
- You need to associate values with unique keys
- You need to look up values using custom identifiers
- You're implementing a cache or memoization system
- You need to represent a mapping relationship between two pieces of data
In SwiftUI specifically:
// Use Array when order matters
struct OrderedListView: View {
let steps = ["Prepare ingredients", "Mix batter", "Bake", "Cool", "Serve"]
var body: some View {
List(steps.indices, id: \.self) { index in
Text("\(index + 1). \(steps[index])")
}
}
}
// Use Set when managing unique selections
struct FilterView: View {
@State private var activeFilters: Set<String> = []
let availableFilters = ["Vegetarian", "Gluten-free", "Dairy-free", "Nut-free"]
var body: some View {
VStack {
ForEach(availableFilters, id: \.self) { filter in
Toggle(filter, isOn: Binding(
get: { activeFilters.contains(filter) },
set: { isActive in
if isActive {
activeFilters.insert(filter)
} else {
activeFilters.remove(filter)
}
}
))
}
}
.padding()
}
}
The key to mastering collection types in SwiftUI is understanding their unique characteristics and choosing the right tool for each specific scenario. Sets excel in situations where uniqueness and fast membership testing are paramount—qualities that appear frequently in reactive UI development.
2. Swift Set Fundamentals
Sets in Swift provide powerful capabilities for working with unique collections of values. Understanding how to create, modify, and manipulate sets is essential for leveraging their full potential in your SwiftUI applications. This section covers the fundamental operations and concepts you'll need to work effectively with sets.
A. Creating and Initializing Sets
Swift offers several approaches to creating and initializing sets, each suited to different scenarios. Understanding these initialization patterns helps you choose the most appropriate and expressive option for your specific needs.
i. Basic set creation syntax
The most common ways to create sets in Swift include:
// Empty set with type annotation
var emptyStringSet: Set<String> = []
// Set with initial values using array literal
let colorSet: Set<String> = ["Red", "Green", "Blue"]
// Set with type inference (requires explicit Set type)
let numberSet: Set = [1, 2, 3, 4, 5]
// Alternative syntax using the Set initializer
var anotherSet = Set<Int>()
// Creating a set from an array (removes duplicates)
let uniqueNumbers = Set([1, 2, 2, 3, 3, 3, 4, 5, 5])
// uniqueNumbers contains [1, 2, 3, 4, 5]
One important point to remember is that, unlike arrays, Swift cannot infer the type when you create a set with an array literal. You must explicitly specify that you're creating a Set
:
// This creates an Array, not a Set
let colors = ["Red", "Green", "Blue"]
// This creates a Set
let colorSet: Set = ["Red", "Green", "Blue"]
// OR
let anotherColorSet = Set(["Red", "Green", "Blue"])
ii. Specialized initializers
Swift's Set
type provides specialized initializers for different scenarios:
// Initialize an empty set
var emptySet = Set<Double>()
// Initialize with a sequence (like an array, range, or another collection)
let setFromRange = Set(1...5)
let setFromArray = Set(["Apple", "Banana", "Cherry"])
// Initialize with a sequence while filtering elements
let evenNumbers = Set(0...10).filter { $0 % 2 == 0 }
// evenNumbers contains [0, 2, 4, 6, 8, 10]
// Initialize with a sequence transformer
let squareSet = Set((1...5).map { $0 * $0 })
// squareSet contains [1, 4, 9, 16, 25]
// You can also combine functional approaches
let filteredTransformed = Set((1...10).filter { $0 % 2 == 1 }.map { $0 * $0 })
// Contains [1, 9, 25, 49, 81] (squares of odd numbers from 1-10)
iii. Initializing sets with custom types
When working with custom types in Swift, you need to ensure they conform to the Hashable
protocol to use them in sets:
// Custom type with Hashable conformance
struct User: Hashable {
let id: UUID
let name: String
let email: String
// Swift can synthesize Hashable conformance for types with only Hashable properties
// For custom hashing behavior, you can implement hash(into:) yourself
}
// Creating a set of custom objects
let user1 = User(id: UUID(), name: "Alice", email: "alice@example.com")
let user2 = User(id: UUID(), name: "Bob", email: "bob@example.com")
let user3 = User(id: UUID(), name: "Charlie", email: "charlie@example.com")
var userSet: Set<User> = [user1, user2, user3]
For custom types, Swift's compiler can automatically synthesize the required Hashable
implementation if all stored properties are themselves Hashable
. This is why simple structs with basic Swift types often work with sets without extra code.
If you need custom hashing behavior, you can implement the hash(into:)
method:
struct Product: Hashable {
let id: String
let name: String
let category: String
let price: Double
// Custom hashing that only considers the ID
// This means two products with the same ID are considered identical
// even if other properties differ
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
// When customizing hash(into:), you also need to implement Equatable
static func == (lhs: Product, rhs: Product) -> Bool {
return lhs.id == rhs.id
}
}
iv. Practical examples in SwiftUI context
In SwiftUI applications, sets are often used to track state information:
struct FilterSelectionView: View {
// Set to track selected filter categories
@State private var selectedCategories: Set<String> = []
let availableCategories = ["Electronics", "Clothing", "Books", "Home", "Sports"]
var body: some View {
VStack {
Text("Select Categories")
.font(.headline)
ForEach(availableCategories, id: \.self) { category in
Toggle(category, isOn: Binding(
get: { selectedCategories.contains(category) },
set: { isOn in
if isOn {
selectedCategories.insert(category)
} else {
selectedCategories.remove(category)
}
}
))
}
Text("Selected: \(selectedCategories.joined(separator: ", "))")
.padding(.top)
}
.padding()
}
}
This example demonstrates how a set naturally represents the selection state in a filter interface, ensuring each category can only be selected once.
B. Basic Set Operations
Sets provide a rich set of operations for adding, removing, and querying elements. Understanding these fundamental operations is essential for working effectively with sets in Swift.
i. Adding and removing elements
Sets provide several methods for adding and removing elements:
var fruitSet: Set<String> = ["Apple", "Banana"]
// Adding elements
fruitSet.insert("Cherry") // Set now contains ["Apple", "Banana", "Cherry"]
// insert() returns a tuple indicating whether the insertion happened
let insertResult = fruitSet.insert("Banana") // Banana already exists
print(insertResult.inserted) // false (element was not inserted)
print(insertResult.memberAfterInsert) // "Banana" (the existing element)
// Removing elements
let removedFruit = fruitSet.remove("Banana") // Returns the removed element
print(removedFruit) // Optional("Banana")
// If the element doesn't exist, remove() returns nil
let nonExistentRemoval = fruitSet.remove("Mango")
print(nonExistentRemoval) // nil
// Remove all elements
fruitSet.removeAll() // Set is now empty
The insert
method is particularly useful because it returns a tuple with two values:
inserted
: A boolean indicating whether the element was newly inserted (true
) or already existed (false
)memberAfterInsert
: The element in the set after the operation, which is either the newly inserted element or the existing one
ii. Checking membership and properties
Sets excel at quickly determining whether they contain specific elements:
let numberSet: Set = [1, 2, 3, 4, 5]
// Check if an element exists
let containsThree = numberSet.contains(3) // true
let containsSix = numberSet.contains(6) // false
// Check if set is empty
let isEmpty = numberSet.isEmpty // false
// Get the count of elements
let count = numberSet.count // 5
// Get the first element (order is not guaranteed)
if let firstElement = numberSet.first {
print(firstElement) // Prints one of the elements (order not guaranteed)
}
The contains
method is exceptionally fast in sets (O(1) constant time complexity), making it ideal for frequent membership testing in performance-critical code.
iii. Iterating through sets
Although sets are unordered, you can still iterate through their elements:
let fruitSet: Set = ["Apple", "Banana", "Cherry", "Date"]
// Basic iteration
for fruit in fruitSet {
print(fruit)
}
// Using forEach
fruitSet.forEach { fruit in
print("I like \(fruit)")
}
// Convert to array for sorted iteration
for fruit in fruitSet.sorted() {
print(fruit)
}
// Filter during iteration
for fruit in fruitSet where fruit.count > 5 {
print("\(fruit) has more than 5 letters")
}
Remember that the iteration order is not guaranteed to be the same across multiple runs or after modifications to the set. If you need a consistent order, convert the set to an array and sort it.
iv. Set algebra operations
One of the most powerful aspects of sets is their ability to perform mathematical set operations:
let setA: Set = [1, 2, 3, 4, 5]
let setB: Set = [4, 5, 6, 7, 8]
// Union: all elements that are in either set
let union = setA.union(setB)
// [1, 2, 3, 4, 5, 6, 7, 8]
// Intersection: only elements that are in both sets
let intersection = setA.intersection(setB)
// [4, 5]
// Difference: elements in setA that aren't in setB
let difference = setA.subtracting(setB)
// [1, 2, 3]
// Symmetric difference: elements in either set but not in both
let symmetricDifference = setA.symmetricDifference(setB)
// [1, 2, 3, 6, 7, 8]
These operations create new sets without modifying the original sets. For in-place mutations, use their "form" counterparts:
var mutableSet: Set = [1, 2, 3]
// In-place union
mutableSet.formUnion([3, 4, 5])
// mutableSet now contains [1, 2, 3, 4, 5]
// In-place intersection
mutableSet.formIntersection([2, 4, 6])
// mutableSet now contains [2, 4]
// In-place subtraction
mutableSet.subtract([2, 3, 4])
// mutableSet now contains [4]
// In-place symmetric difference
mutableSet.formSymmetricDifference([4, 5, 6])
// mutableSet now contains [5, 6]
v. Set comparison operations
Sets provide methods to compare their relationship with other sets:
let superSet: Set = [1, 2, 3, 4, 5]
let subSet: Set = [3, 4]
let overlappingSet: Set = [4, 5, 6]
let disjointSet: Set = [7, 8, 9]
// Check if a set is a subset of another
print(subSet.isSubset(of: superSet)) // true
// Check if a set is a superset of another
print(superSet.isSuperset(of: subSet)) // true
// Check if a set is a strict subset (subset but not equal)
print(subSet.isStrictSubset(of: superSet)) // true
print(superSet.isStrictSubset(of: superSet)) // false
// Check if a set is a strict superset (superset but not equal)
print(superSet.isStrictSuperset(of: subSet)) // true
print(superSet.isStrictSuperset(of: superSet)) // false
// Check if sets have elements in common
print(superSet.isDisjoint(with: disjointSet)) // true (no common elements)
print(superSet.isDisjoint(with: overlappingSet)) // false (have common elements)
These comparison operations are particularly useful when implementing logic that depends on the relationship between different sets, such as checking if a user has all required permissions or if two feature sets overlap.
C. Mutability and Immutability
Understanding how mutability works with sets in Swift is crucial for creating robust and predictable code, especially in the context of SwiftUI's state management.
i. Mutable vs. immutable sets
Like other Swift types, sets can be declared as either mutable or immutable:
// Immutable set (cannot be modified after creation)
let immutableSet: Set = [1, 2, 3]
// Attempting to modify an immutable set causes a compiler error
// immutableSet.insert(4) // Error: Cannot use mutating member on immutable value
// Mutable set (can be modified after creation)
var mutableSet: Set = [1, 2, 3]
mutableSet.insert(4) // Works fine
This distinction is enforced at compile time, helping you express your intent about whether a set should be changeable and preventing accidental modifications.
ii. Value semantics and copying behavior
Sets in Swift have value semantics, meaning they are copied when assigned to a new variable or passed to a function:
var originalSet: Set = [1, 2, 3]
var copiedSet = originalSet // Creates a copy, not a reference
// Modifying the copy does not affect the original
copiedSet.insert(4)
print(originalSet) // [1, 2, 3]
print(copiedSet) // [1, 2, 3, 4]
This behavior is particularly important in SwiftUI, which relies on value semantics for its state management system:
struct ContentView: View {
@State private var selectedTags: Set<String> = ["Swift", "SwiftUI"]
var body: some View {
VStack {
// When this button is tapped, a copy of the set is modified,
// which then triggers a view update due to @State
Button("Add Tag") {
selectedTags.insert("iOS")
}
List(Array(selectedTags), id: \.self) { tag in
Text(tag)
}
}
}
}
Value semantics ensure that modifications create new values rather than changing shared state, which helps prevent subtle bugs in concurrent or reactive code.
iii. Sets in SwiftUI state management
SwiftUI's state management system works seamlessly with sets thanks to their value semantics:
struct TagSelectionView: View {
// Using Set for state management
@State private var selectedTags: Set<String> = []
let availableTags = ["Swift", "SwiftUI", "iOS", "macOS", "watchOS", "tvOS"]
var body: some View {
VStack {
Text("Selected: \(selectedTags.count) tags")
.font(.headline)
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))]) {
ForEach(availableTags, id: \.self) { tag in
TagView(
tag: tag,
isSelected: selectedTags.contains(tag),
onTap: {
// Toggle selection state
if selectedTags.contains(tag) {
selectedTags.remove(tag)
} else {
selectedTags.insert(tag)
}
}
)
}
}
.padding()
}
Button("Clear All") {
selectedTags.removeAll()
}
.disabled(selectedTags.isEmpty)
.padding()
}
}
}
struct TagView: View {
let tag: String
let isSelected: Bool
let onTap: () -> Void
var body: some View {
Text(tag)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(isSelected ? Color.blue : Color.gray.opacity(0.3))
.foregroundColor(isSelected ? .white : .primary)
.cornerRadius(20)
.onTapGesture(perform: onTap)
}
}
When the user selects or deselects a tag, the state is updated by modifying the set, which then triggers a view update. The set ensures that each tag can only be selected once, naturally enforcing the uniqueness constraint.
iv. Functional programming with sets
Sets support functional programming patterns through higher-order functions:
let numberSet: Set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Map: transform all elements (returns an array, not a set)
let doubled = numberSet.map { $0 * 2 }
// [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
// To get a Set result, create a new set from the transformed elements
let doubledSet = Set(numberSet.map { $0 * 2 })
// Filter: get elements matching a condition
let evenNumbers = numberSet.filter { $0 % 2 == 0 }
// [2, 4, 6, 8, 10]
// Reduce: combine all elements into a single value
let sum = numberSet.reduce(0, +)
// 55
// CompactMap: transform and filter out nil results
let strings: Set = ["1", "2", "three", "4", "five"]
let validNumbers = Set(strings.compactMap { Int($0) })
// [1, 2, 4]
Note that map
and filter
return arrays, not sets. If you want a set result, you need to create a new set from the result. This is because the transformed elements might not be unique or might not conform to Hashable
.
v. Thread safety and concurrency considerations
When working with sets in concurrent code, the value semantics of sets provide important safety guarantees:
let originalSet: Set = [1, 2, 3]
// In concurrent code, each closure gets its own copy
DispatchQueue.global().async {
var localCopy = originalSet
localCopy.insert(4)
print("Async: \(localCopy)")
}
// Original remains unchanged
print("Original: \(originalSet)")
This becomes particularly important in SwiftUI applications where views might be updated from background threads, such as when receiving network responses or processing data. The value semantics ensure that concurrent modifications don't lead to race conditions or unexpected behavior.
In SwiftUI views, you can generally rely on SwiftUI's state management to handle updates safely. However, when working with sets in actor-based concurrency or other multithreaded contexts, be mindful of how and where modifications happen:
actor TagStore {
private var tags: Set<String> = []
func addTag(_ tag: String) {
tags.insert(tag)
}
func removeTag(_ tag: String) {
tags.remove(tag)
}
func getAllTags() -> Set<String> {
// Returns a copy due to value semantics
return tags
}
}
// When using TagStore in SwiftUI
struct TagManagerView: View {
let tagStore: TagStore
@State private var localTags: Set<String> = []
@State private var newTag = ""
var body: some View {
VStack {
// UI elements...
Button("Refresh Tags") {
Task {
// Safely update state from async context
localTags = await tagStore.getAllTags()
}
}
}
.task {
// Load initial data
localTags = await tagStore.getAllTags()
}
}
}
The value semantics of sets work harmoniously with Swift's concurrency model, making them a safe choice for shared state in concurrent code. Understanding these fundamental aspects of sets in Swift—creating them, performing basic operations, and managing mutability—provides the foundation for using sets effectively in your SwiftUI applications.
3. Working with Sets in SwiftUI
Sets provide powerful capabilities specifically suited to SwiftUI development, offering elegant solutions for state management, data organization, and performance optimization. In this section, we'll explore practical applications of sets within the SwiftUI framework, showing how they can enhance your applications' functionality, maintainability, and performance.
Open the source code for real examples generated with AI.
A. Data Management with Sets
SwiftUI applications frequently need to manage collections of unique data efficiently. Sets provide natural solutions for many common data management scenarios.
i. Managing unique identifiers (Demo 3Ai)
This SwiftUI application demonstrates an efficient approach to product catalog management by combining an array with a Set data structure. This implementation pattern elegantly addresses a common performance challenge in collection management by using the appropriate data structure for each operation—maintaining ordered iteration through arrays while achieving constant-time lookups through Sets.
ii. Tag and category systems (Demo 3Aii)
This SwiftUI application demonstrates an elegant tag-based filtering system using Sets for efficient content management. This implementation showcases how Sets provide both performance benefits and semantic clarity when working with collections where uniqueness and membership testing are primary operations.
iii. Deduplication in data pipelines (Demo 3Aiii)
This SwiftUI application showcases an advanced data processing system that leverages Sets for efficient deduplication across multiple data sources. This educational implementation clearly illustrates how Sets excel at handling scenarios requiring uniqueness guarantees and membership testing across large collections, while the detailed logging system helps visualize the efficiency gains compared to array-only approaches that would require costly linear searches to identify duplicates.
iv. Data validation and integrity (Demo 3Aiv)
This SwiftUI application demonstrates an advanced form validation system that leverages Sets for efficient data validation and error handling. This practical demonstration illustrates how Sets provide both semantic clarity and significant performance advantages over arrays when validating form data, especially when working with predefined collections of restricted values or when checking for missing required fields.
B. State Management Using Sets
SwiftUI's reactive programming model works exceptionally well with sets for managing application state, especially for selection states, filters, and toggles.
i. Managing multi-selection state (Demo 3Bi)
This SwiftUI application demonstrates a sophisticated multi-selection implementation that leverages Sets for optimal performance and clean code structure. The demo provides both practical functionality through the interactive UI and theoretical understanding through the informational view, effectively teaching users not just how to implement multi-selection but why Sets are the optimal data structure for this common UI pattern. This pattern is immediately applicable in many real-world scenarios like filtering interfaces, batch operations on collections, and any situation requiring efficient state tracking of selected items.
ii. Filter state management (Demo 3Bii)
This SwiftUI application demonstrates a practical product filtering system that leverages Sets for efficient filter state management across multiple criteria. The code includes both a standalone filter view and an interactive demo with pre-selected filters that demonstrates real-world data binding, showcasing how Sets provide a clean, performant solution for managing multi-criteria filtering interfaces. This pattern is directly applicable to e-commerce applications, content libraries, or any interface requiring users to filter collections by multiple overlapping criteria, with Sets ensuring the UI remains responsive even as the number of filter options or selected items grows.
iii. Toggle groups and mutually exclusive options (Demo 3Biii)
This SwiftUI code implements an advanced settings management system that transcends traditional feature toggling by leveraging Swift's powerful type system and Set operations. The approach demonstrates a nuanced state management technique that provides users with a flexible, intuitive settings experience while maintaining robust programmatic control, making it an exemplary implementation of declarative UI design in SwiftUI that can be easily adapted to various complex application scenarios.
iv. Permissions and capability management (Demo 3Biv)
This SwiftUI code demonstrates a sophisticated role-based access control (RBAC) system that leverages Swift's powerful type system and Set operations to manage user permissions with exceptional flexibility and granularity. The implementation introduces a comprehensive permission management model through three key components: a Permission
enum defining granular access rights, a Role
struct representing predefined permission sets, and a User
class that dynamically calculates effective permissions by combining assigned roles and custom permissions. Sets offer powerful performance advantages that can significantly improve SwiftUI applications. While some performance optimizations might seem subtle, they become critical as your application scales or when dealing with large datasets. Understanding these optimization techniques can help you create more responsive and efficient SwiftUI interfaces.
C. Performance Optimization with Sets
Sets offer powerful performance advantages that can significantly improve SwiftUI applications. While some performance optimizations might seem subtle, they become critical as your application scales or when dealing with large datasets. Understanding these optimization techniques can help you create more responsive and efficient SwiftUI interfaces.
i. Efficient membership testing
Sets excel at quickly determining whether they contain a specific element. This operation occurs in constant time (O(1)) regardless of the set's size, unlike arrays which require linear time (O(n)) to search through all elements.
In SwiftUI, this becomes particularly valuable when checking if an item is selected, favorited, or belongs to a specific category. For instance, when rendering a list with hundreds of items where some are selected, checking selection status with a set is dramatically faster than searching through an array of selected items. As your application scales, this performance difference becomes increasingly noticeable, potentially preventing UI lag and ensuring smooth animations.
The performance impact is most significant in operations that run frequently, such as during scrolling or when filtering large datasets where membership tests must be performed repeatedly.
ii. Caching and memoization
Sets provide an elegant solution for implementing caching mechanisms to avoid redundant operations. By tracking which operations have already been performed or which resources have been loaded, you can prevent unnecessary work.
In SwiftUI applications, this pattern helps avoid recomputing values, re-fetching resources, or redrawing views that haven't changed. For example, you can use sets to track which images have already been loaded, which calculations have been performed, or which network requests have been initiated.
The result is decreased CPU usage, reduced memory consumption, lower battery drain, and a more responsive user interface. This is especially valuable in resource-intensive applications or when working with limited device capabilities. Proper caching with sets helps establish clear boundaries around expensive operations, ensuring they only execute when absolutely necessary.
iii. Preventing redundant calculations and view updates
SwiftUI's reactive programming model updates the UI whenever state changes. By using sets to precisely track which items need updates, you can minimize unnecessary view recalculations and redraws.
Rather than marking entire collections as needing updates, sets allow you to pinpoint exactly which items have changed. This selective approach to updates means SwiftUI only needs to regenerate the relevant portions of the view hierarchy. The result is more efficient rendering and smoother animations, particularly when working with complex interfaces or large datasets.
This granular tracking becomes especially important in applications with real-time data updates, collaborative features, or complex state management where being precise about what needs to change directly impacts application performance.
iv. Optimizing search and filtering operations
Sets enable highly efficient search and filtering implementations that remain performant even as data volumes grow. By using inverted indices (where each filter value maps to a set of matching item IDs) and leveraging set operations like union and intersection, you can implement sophisticated filtering systems that scale beautifully.
For example, when implementing a product catalog with multiple filter criteria (price, category, brand, etc.), sets allow you to quickly combine these criteria through mathematical set operations. This approach maintains consistent performance regardless of how many filters are applied, unlike array-based filtering which becomes increasingly expensive with each additional criterion.
These optimized filtering techniques are particularly valuable for search interfaces, data visualization components, and any feature where users need to quickly narrow down large datasets according to multiple criteria.
4. Advanced Set Operations
Sets in Swift offer powerful capabilities beyond basic operations. When you master advanced set operations, you can solve complex problems with elegant, efficient code. This section explores sophisticated aspects of sets that can elevate your SwiftUI applications.
A. Set Algebra (Union, Intersection, etc.)
Set algebra operations allow you to perform mathematical operations on sets that produce new sets based on specific relationships. These operations form the foundation for many advanced algorithms and data processing techniques.
i. Understanding mathematical set operations
Set algebra is rooted in mathematical set theory, providing powerful operations for combining and comparing sets. Swift implements these operations with highly optimized code.
The fundamental set operations include:
Union (∪): Combines elements from both sets, removing duplicates automatically. This operation creates a new set containing all elements that appear in either or both sets.
Intersection (∩): Creates a new set containing only elements that appear in both sets. This finds the common elements between two sets.
Difference (−): Creates a new set containing elements from the first set that don't appear in the second set. This essentially "subtracts" one set from another.
Symmetric Difference (△): Creates a new set containing elements that appear in either set but not in both. This is equivalent to the union minus the intersection.
For example, imagine you have two sets of fruits:
let basketA: Set = ["Apple", "Banana", "Orange", "Pear"]
let basketB: Set = ["Banana", "Grapefruit", "Orange", "Kiwi"]
The union would be all fruits from both baskets without duplicates: ["Apple", "Banana", "Orange", "Pear", "Grapefruit", "Kiwi"]
.
The intersection would be only fruits present in both baskets: ["Banana", "Orange"]
.
ii. Set operations in Swift syntax
Swift provides both non-mutating methods that return new sets and mutating methods that modify sets in place.
Non-mutating operations:
// Union: all fruits from either basket
let allFruits = basketA.union(basketB)
// ["Apple", "Banana", "Orange", "Pear", "Grapefruit", "Kiwi"]
// Intersection: fruits common to both baskets
let commonFruits = basketA.intersection(basketB)
// ["Banana", "Orange"]
// Difference: fruits in A but not in B
let onlyInA = basketA.subtracting(basketB)
// ["Apple", "Pear"]
// Symmetric difference: fruits in either basket but not both
let uniqueFruits = basketA.symmetricDifference(basketB)
// ["Apple", "Pear", "Grapefruit", "Kiwi"]
Mutating operations modify the set in place, which is more efficient when you don't need the original set:
var fruitsCollection: Set = ["Apple", "Banana"]
fruitsCollection.formUnion(["Banana", "Kiwi"])
// fruitsCollection is now ["Apple", "Banana", "Kiwi"]
iii. Set algebra for solving complex problems
Set algebra provides elegant solutions for many challenging problems in SwiftUI applications:
Finding items matching multiple criteria: For example, if you have sets of products that are "on sale" and products that are "in stock", you can find products that are both on sale AND in stock with a simple intersection:
let onSaleProducts: Set = [1001, 1002, 1003, 1005]
let inStockProducts: Set = [1002, 1003, 1004, 1006]
// Products both on sale AND in stock
let availableDeals = onSaleProducts.intersection(inStockProducts)
// [1002, 1003]
Creating composite filters: Union operations allow you to combine filter criteria with OR logic:
let featuredProducts: Set = [2001, 2003, 2005]
let newArrivals: Set = [2002, 2004, 2005]
// Products that are either featured OR new arrivals
let promotedProducts = featuredProducts.union(newArrivals)
// [2001, 2002, 2003, 2004, 2005]
B. Working with Custom Types in Sets
Making your custom types work with sets requires understanding how sets determine equality and calculate hash values.
i. Hashable protocol requirements and implementation
To store a custom type in a set, it must conform to the Hashable
protocol, which inherits from Equatable
. This means implementing:
- The
==
operator to define when two instances are considered equal - A method to generate a hash value for each instance
A simple example with a custom User
type:
struct User: Hashable {
let id: Int
var name: String
var email: String
// Two users are equal if they have the same ID
static func == (lhs: User, rhs: User) -> Bool {
return lhs.id == rhs.id
}
// Only hash based on the id property
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
// Now we can use User in a Set
var users: Set<User> = []
users.insert(User(id: 1, name: "Alice", email: "alice@example.com"))
ii. Auto-synthesis of Hashable for structs and enums
Swift can automatically generate Hashable
conformance for structs and enums if all their stored properties or associated values are themselves Hashable
:
// No manual implementation needed - Swift generates it
struct Product: Hashable {
let id: UUID
let name: String
let price: Double
}
// Now we can create a set of products
let featuredProducts: Set<Product> = [
Product(id: UUID(), name: "Phone", price: 999),
Product(id: UUID(), name: "Tablet", price: 499)
]
iii. Custom hashing implementation
Sometimes you'll want to customize how hashing works, particularly when only certain properties should determine identity:
struct DatabaseEntity: Hashable {
let id: Int
var name: String
var lastModified: Date
var data: [String: Any]
// Two entities are the same if they have the same ID,
// regardless of other properties
static func == (lhs: DatabaseEntity, rhs: DatabaseEntity) -> Bool {
return lhs.id == rhs.id
}
// Only hash based on the id
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
// This allows us to find entities by ID in a set, even if other properties differ
var entities: Set<DatabaseEntity> = [/* ... */]
let searchID = 42
if let entity = entities.first(where: { $0.id == searchID }) {
print("Found entity: \(entity.name)")
}
C. Sets for Complex Data Filtering
Sets truly shine when implementing sophisticated filtering mechanisms. Their mathematical operations provide elegant solutions for complex filtering logic.
i. Building complex filter expressions with set operations
Set operations naturally express boolean logic for filtering:
// Define sets of product IDs for various criteria
let categoryA: Set = [1, 2, 3, 4]
let categoryB: Set = [3, 4, 5, 6]
let onSale: Set = [2, 4, 6, 8]
let outOfStock: Set = [1, 6, 9]
// Products in either category A OR category B
let categoryAOrB = categoryA.union(categoryB)
// [1, 2, 3, 4, 5, 6]
// Products that are (in category A OR B) AND on sale
let onSaleInCategories = categoryAOrB.intersection(onSale)
// [2, 4, 6]
// Products that are (in category A OR B) AND on sale BUT NOT out of stock
let availableDeals = onSaleInCategories.subtracting(outOfStock)
// [2, 4]
This declarative approach is more readable than complex conditional logic and scales beautifully as filtering criteria grow.
ii. Implementing advanced filtering patterns
Sets enable sophisticated filtering patterns in SwiftUI applications, such as faceted search where some filters combine as AND conditions and others as OR conditions:
// Color filters (OR relationship within category)
let redProducts: Set = [101, 102, 105]
let blueProducts: Set = [103, 104, 105]
let selectedColors: Set = [redProducts, blueProducts].reduce(into: Set<Int>()) {
$0.formUnion($1)
}
// [101, 102, 103, 104, 105]
// Size filters (OR relationship within category)
let smallProducts: Set = [101, 103, 106]
let mediumProducts: Set = [102, 104, 105]
let selectedSizes: Set = [smallProducts, mediumProducts].reduce(into: Set<Int>()) {
$0.formUnion($1)
}
// [101, 102, 103, 104, 105, 106]
// Between different categories, we apply AND logic
let filteredProducts = selectedColors.intersection(selectedSizes)
// [101, 102, 103, 104, 105]
iii. Optimizing multi-criteria filtering
For highly optimized filtering, we can build inverted indices that map attributes to sets of items with those attributes:
// Inverted indices mapping attributes to product IDs
let productsByCategory: [String: Set<Int>] = [
"electronics": [1, 2, 3, 4],
"clothing": [5, 6, 7],
"books": [8, 9, 10]
]
let productsByBrand: [String: Set<Int>] = [
"apple": [1, 3],
"samsung": [2, 4],
"nike": [5, 6]
]
// Find products that are in electronics category AND made by samsung
if let electronicsProducts = productsByCategory["electronics"],
let samsungProducts = productsByBrand["samsung"] {
let samsungElectronics = electronicsProducts.intersection(samsungProducts)
// [2, 4]
}
iv. Real-world filtering example: Tag-based content filtering
A common real-world example is filtering content by tags, where users can select multiple tags and see items that match all their selections:
// Content items with tags
struct ContentItem: Identifiable {
let id: Int
let title: String
let tags: Set<String>
}
let library = [
ContentItem(id: 1, title: "SwiftUI Basics", tags: ["iOS", "SwiftUI", "Beginner"]),
ContentItem(id: 2, title: "Advanced Animations", tags: ["iOS", "SwiftUI", "Advanced"]),
ContentItem(id: 3, title: "Core Data Fundamentals", tags: ["iOS", "Data", "Beginner"]),
ContentItem(id: 4, title: "SwiftUI Architecture", tags: ["iOS", "SwiftUI", "Architecture"])
]
// User selected tags (we want items that have ALL these tags)
let selectedTags: Set<String> = ["iOS", "SwiftUI"]
// Filter content items that have all selected tags
let filteredContent = library.filter { item in
selectedTags.isSubset(of: item.tags)
}
// Returns items 1, 2, and 4
// We could also find items that match ANY selected tag
let anyTagMatches = library.filter { item in
!selectedTags.isDisjoint(with: item.tags)
}
// Returns all items
5. Conclusion
Sets are a powerful and often underutilized tool in Swift development. Throughout this tutorial, we've explored how sets provide unique capabilities that can transform your approach to SwiftUI development—enabling more efficient code, clearer intent, and better performance for many common scenarios.
Sets embody an elegant concept: collections of unique values without defined order, optimized for membership testing and set-theoretic operations. This seemingly simple definition unlocks sophisticated capabilities that can significantly enhance your SwiftUI applications.
Learn with videos and source files. Available to Pro subscribers only.
Purchase includes access to 50+ courses, 320+ premium tutorials, 300+ hours of videos, source files and certificates.
Templates and source code
Download source files
Download the videos and assets to refer and learn offline without interuption.
Design template
Source code for all sections
Video files, ePub and subtitles
Videos
Assets
1
Building Your iOS Development Foundation
Master the fundamentals of Swift programming with hands-on examples designed for beginners and experienced developers alike
2
SwiftUI Print Debugging
Print debugging: Unlock the invisible processes with strategic print statements that illuminate state changes, view lifecycles and data flow
18:04
3
Comments Documentation Waypoints
Transform your code from mysterious instructions to a comprehensive narrative with strategic comments that explain the why
22:02
4
Variables and Constants
Learn when and how to use variables and constants to write safer, more efficient SwiftUI code
11:37
5
Strings and Interpolation
Learn essential string operations in Swift: Build better iOS apps with efficient text handling techniques
13:22
6
Swift Operators: The Foundation of SwiftUI Logic
Building powerful iOS apps through the language of operations
5:34
7
Swift Unary Operators
Mastering the elegant simplicity of unary operators for cleaner, more expressive SwiftUI code that transforms your UI with minimal syntax
15:00
8
Swift Binary Operators
Master the two-operand symbols that transform complex interface logic into concise, readable declarations
3:36
9
Arithmetic Operators
Learn how to implement and optimize arithmetic operations in SwiftUI, from basic calculations to complex mathematical interfaces
6:11
10
If-Else and Comparison Operators
Building Dynamic SwiftUI: Mastering If-Else and Comparison Operators
12:32
11
Logical Operators
Master SwiftUI's logical operators: Building intelligent iOS apps with robust decision-making systems
6:03
12
Ternary Operators
Use the power of Swift's ternary conditional operator to create dynamic, responsive interfaces with minimal code in SwiftUI
13
Blocks and Scope
A comprehensive guide to writing clean, organized code through proper variable management and state control
10:22
14
Swift Collections: Arrays, Sets, and Dictionaries Overview
Organize Your Data Effectively: Learn How to Choose and Optimize the Perfect Collection Type for Your SwiftUI Applications
15
Swift Arrays: The Basics Part 1
Master essential array operations and manipulations to build a solid foundation for iOS development
16
Swift Arrays: Best Practices in SwiftUI Part 2
Integrate arrays with SwiftUI, optimize performance, and implement professional-grade patterns for production apps
17
Swift Sets
From Basics to Advanced: Swift Set Techniques for Better Apps
Meet the instructor
We all try to be consistent with our way of teaching step-by-step, providing source files and prioritizing design in our courses.
Sourasith Phomhome
UI Designer
Designer at Design+Code
20 courses - 77 hours

Master Agentic Workflows
In this course, you’ll learn how to add agents to your workflows. An agent workflow is more than just a simple automation. Instead of following a fixed script, agents can make decisions, adjust to changes, and figure out the best way to complete a task. We’ll start by exploring what MCP servers are and all the new possibilities they bring. Then, we’ll dive into agentic frameworks that make it easy to build flexible, helpful agents that can take care of your everyday tasks.
2 hrs

Design Multiple Apps with Figma and AI
In this course, you’ll learn to design multiple apps using Figma and AI-powered tools, tackling a variety of real-world UI challenges. Each week, a new episode will guide you through a different design, helping you master essential UI/UX principles and workflows
4 hrs

SwiftUI Fundamentals Handbook
A comprehensive guide to mastering Swift programming fundamentals, designed for aspiring iOS developers. This handbook provides a structured approach to learning Swift's core concepts, from basic syntax to advanced programming patterns. Through carefully sequenced chapters, readers will progress from essential programming concepts to object-oriented principles, building a solid foundation for SwiftUI development. Each topic includes practical examples and clear explanations, ensuring a thorough understanding of Swift's capabilities. This handbook serves as both a learning resource and a reference guide, covering fundamental concepts required for modern iOS development. Topics are presented in a logical progression, allowing readers to build their knowledge systematically while gaining practical programming skills.
1 hrs

Design and Code User Interfaces with Galileo and Claude AI
In this course, you’ll learn how to use AI tools to make UI/UX design faster and more efficient. We’ll start with Galileo AI to create basic designs, providing a solid foundation for your ideas. Next, we’ll refine these designs in Figma to match your personal style, and finally, we’ll use Claude AI to turn them into working code—eliminating the need for traditional prototyping.
4 hrs

Build a React Native app with Claude AI
This comprehensive course explores the integration of cutting-edge AI tools into the React Native development workflow, revolutionizing the approach to mobile application creation. Participants will learn to leverage AI-powered platforms such as Claude and Locofy to expedite coding processes, enhance problem-solving capabilities, and optimize productivity.
14 hrs

Design and Prototype for iOS 18
Design and Prototype for iOS 18 is an immersive course that equips you with the skills to create stunning, user-friendly mobile applications. From mastering Figma to understanding iOS 18's latest design principles, you'll learn to craft two real-world apps - a Car Control interface and an AI assistant.
3 hrs

Master Responsive Layouts in Figma
Creating responsive layouts is a must-have skill for any UI/UX designer. With so many different devices and screen sizes, designing interfaces that look great and work well on all platforms is necessary. Mastering this skill will make you stand out in the field. In this course, we'll start from scratch to create this beautiful design using Figma. You'll learn how to make layouts that are easy to use and work well on any device. We'll cover key concepts and tools to help you master responsive design in Figma.
2 hrs

UI UX Design with Mobbin and Figma
Mobbin is a powerful tool for UI/UX designers seeking inspiration and innovative design solutions. This platform offers a vast collection of real-world mobile app designs, providing a treasure trove of UI elements and layouts.
2 hrs

3D UI Interactive Web Design with Spline
Learn to create 3D designs and UI interactions such as 3D icons, UI animations, components, variables, screen resize, scrolling interactions, as well as exporting, optimizing, and publishing your 3D assets on websites
3 hrs

Design and Prototype for iOS 17 in Figma
Crafting engaging experiences for iOS 17 and visionOS using the Figma design tool. Learn about Figma's new prototyping features, Dev Mode, variables and auto layout.
6 hrs

Design and Prototype Apps with Midjourney
A comprehensive course on transforming Midjourney concepts into interactive prototypes using essential design techniques and AI tools
8 hrs

iOS Design with Midjourney and Figma
Learn the fundamentals of App UI design and master the art of creating beautiful and intuitive user interfaces for mobile applications
1 hrs

UI Design for iOS, Android and Web in Sketch
Create a UI design from scratch using Smart Layout, Components, Prototyping in Sketch app
1 hrs

UI Design a Camera App in Figma
Design a dark, vibrant and curvy app design from scratch in Figma. Design glass icons, lens strokes and realistic buttons.
1 hrs

UI Design for iOS 16 in Sketch
A complete guide to designing for iOS 16 with videos, examples and design files
3 hrs

Prototyping in Figma
Learn the basics of prototyping in Figma by creating interactive flows from custom designs
1 hrs

UI Design Quick Websites in Figma
Learn how to design a portfolio web UI from scratch in Figma
1 hrs

UI Design Android Apps in Figma
Design Android application UIs from scratch using various tricks and techniques in Figma
2 hrs

UI Design Quick Apps in Figma
Design application UIs from scratch using various tricks and techniques in Figma
12 hrs

Figma Handbook
A comprehensive guide to the best tips and tricks in Figma
6 hrs