Using the Sendable Protocol for Thread Safety in Swift
📖 Scenario: You are building a simple Swift program that shares data safely between threads. Swift's Sendable protocol helps ensure data can be passed between threads without causing problems.
🎯 Goal: Learn how to mark a custom struct as Sendable and use it safely across threads.
📋 What You'll Learn
Create a struct called Message with a text property of type String
Make Message conform to the Sendable protocol
Create a constant message of type Message with the text "Hello from thread!"
Use DispatchQueue.global().async to print the message.text safely from a background thread
💡 Why This Matters
🌍 Real World
In real apps, data often moves between threads. Marking data as Sendable helps prevent bugs and crashes when sharing data safely.
💼 Career
Understanding Sendable is important for Swift developers working on apps that use concurrency, such as iOS apps with background tasks.
Progress0 / 4 steps
1
Create the Message struct
Create a struct called Message with a single property text of type String.
Swift
Hint
Use struct Message { let text: String } to create the struct.
2
Make Message conform to Sendable
Make the Message struct conform to the Sendable protocol by adding : Sendable after the struct name.
Swift
Hint
Add : Sendable right after Message in the struct declaration.
3
Create a Message instance
Create a constant called message of type Message with the text exactly set to "Hello from thread!".
Swift
Hint
Use let message = Message(text: "Hello from thread!") to create the instance.
4
Print message.text safely from a background thread
Use DispatchQueue.global().async to print message.text from a background thread.
Swift
Hint
Use DispatchQueue.global().async { print(message.text) } to print safely on a background thread.
Practice
(1/5)
1. What does the Sendable protocol in Swift ensure?
easy
A. That a function runs asynchronously.
B. That a class can only be used on the main thread.
C. That a variable is immutable.
D. That data can be safely shared between threads without causing race conditions.
Solution
Step 1: Understand the purpose of Sendable
The Sendable protocol marks types that can be safely passed between threads without causing data races.
Step 2: Compare options with the definition
Only That data can be safely shared between threads without causing race conditions. correctly describes this safety guarantee. Other options describe unrelated concepts.
Final Answer:
That data can be safely shared between threads without causing race conditions. -> Option D
Quick Check:
Sendable = safe cross-thread data sharing [OK]
Hint: Sendable means safe to share data across threads [OK]
Common Mistakes:
Confusing Sendable with immutability
Thinking Sendable restricts to main thread only
Assuming Sendable makes functions async
2. Which of the following is the correct way to declare a struct as Sendable in Swift?
easy
A. struct Data { var value: Int } implements Sendable
B. struct Data: Sendable { var value: Int }
C. struct Data Sendable { var value: Int }
D. struct Data { var value: Int } : Sendable
Solution
Step 1: Recall Swift protocol conformance syntax
In Swift, a type conforms to a protocol by listing it after a colon following the type name.
Step 2: Match syntax to options
struct Data: Sendable { var value: Int } uses correct syntax: struct Data: Sendable { ... }. Others are invalid Swift syntax.
Final Answer:
struct Data: Sendable { var value: Int } -> Option B
Quick Check:
Protocol conformance uses colon after type name [OK]
Hint: Use colon after struct name to conform to Sendable [OK]
Common Mistakes:
Placing protocol after braces
Using 'implements' keyword (not Swift)
Omitting colon between type and protocol
3. What will happen when you try to compile this Swift code?
struct Counter: Sendable {
var count: Int
}
let counter = Counter(count: 5)
Task {
print(counter.count)
}
medium
A. It compiles and prints 5.
B. It causes a compile-time error because Counter is not Sendable.
C. It causes a runtime error due to thread safety violation.
D. It compiles but prints 0.
Solution
Step 1: Check if Counter conforms to Sendable
The struct explicitly conforms to Sendable and contains only an Int, which is Sendable.
Step 2: Understand Task usage
The Task runs asynchronously but can safely access counter because it is Sendable.
Final Answer:
It compiles and prints 5. -> Option A
Quick Check:
Sendable struct with Int prints value safely [OK]
Hint: Sendable structs with simple types compile and run safely [OK]
Common Mistakes:
Assuming compile error without checking conformance
Confusing runtime errors with compile errors
Thinking default structs are not Sendable
4. Identify the error in this Swift code using Sendable:
class DataHolder: Sendable {
var data: [Int]
init(data: [Int]) {
self.data = data
}
}
medium
A. Missing explicit Sendable conformance on Array.
B. Class cannot conform to Sendable at all.
C. Array<Int> is not Sendable by default, causing a compile error.
D. No error; code compiles fine.
Solution
Step 1: Check Sendable conformance for class with mutable property
Classes with mutable stored properties like arrays are not automatically Sendable.
Step 2: Understand why Array<Int> is not Sendable by default
Array is a reference type and mutable, so compiler disallows automatic Sendable conformance without extra guarantees.
Final Answer:
Array<Int> is not Sendable by default, causing a compile error. -> Option C