Skip to content

Commit 5de4e2e

Browse files
committed
Understanding TaskLocal in Swift Concurrency
1 parent c45f88d commit 5de4e2e

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
title: 'Understanding TaskLocal in Swift Concurrency'
3+
author: 'Clive Liu'
4+
layout: post
5+
tags: [Swift, Concurrency]
6+
---
7+
8+
`TaskLocal` is a mechanism within Swift’s concurrency system that allows you to store and access values that are local to a task and its child tasks. It’s similar to thread-local storage from the pre-concurrency days, but tailored for Swift’s structured concurrency model.
9+
10+
Imagine you’re writing code and want to pass contextual information—like a tracing context—throughout the call stack without explicitly passing it into every function. That’s exactly the kind of scenario `TaskLocal` is designed to simplify. Think of it like SwiftUI’s environment values: data flows from parent to child, and any descendant can access it without needing every function in the call chain to propagate it manually.
11+
12+
## Usage
13+
14+
Here’s how to define and use a task-local value:
15+
16+
```swift
17+
enum MetricsReporter {
18+
// Must be declared as static properties (below Swift 6.0)
19+
@TaskLocal static var workflowID: UUID?
20+
}
21+
22+
// Global task-local properties are supported starting with Swift 6.0
23+
@TaskLocal var workflowID: UUID?
24+
```
25+
26+
To set a task-local value, you must use the `withValue` function:
27+
28+
```swift
29+
await $workflowID.withValue(.init()) {
30+
await myAmazingWorkflow()
31+
32+
Task {
33+
await myOtherAmazingWorkflow()
34+
}
35+
36+
Task.detached {
37+
// Detached tasks do NOT inherit TaskLocal values.
38+
}
39+
}
40+
```
41+
42+
Within `myAmazingWorkflow()`, `myOtherAmazingWorkflow()`, and any functions they call, `workflowID` will return the value assigned via `withValue`. However, **detached tasks** do **not** inherit task-local values—they start with a clean slate.
43+
44+
## Example
45+
46+
Here’s a full example to demonstrate `TaskLocal` in action:
47+
48+
```swift
49+
@TaskLocal var workflowID: UUID?
50+
51+
func log(_ message: String) {
52+
print("\(workflowID) \(message)")
53+
}
54+
55+
func step1() async {
56+
// do work
57+
log("step1 completed")
58+
}
59+
60+
func step2() async {
61+
// do work
62+
log("step2 completed")
63+
}
64+
65+
func step3() async {
66+
// do work
67+
log("step3 completed")
68+
}
69+
70+
func myAmazingWorkflow() async {
71+
await step1()
72+
await step2()
73+
await step3()
74+
}
75+
76+
Task {
77+
await withDiscardingTaskGroup { group in
78+
for _ in 0..<3 {
79+
group.addTask {
80+
await $workflowID.withValue(.init()) {
81+
await myAmazingWorkflow()
82+
}
83+
}
84+
}
85+
}
86+
}
87+
```
88+
89+
**Sample Output:**
90+
91+
```
92+
Optional(36A1DF29-CF82-4706-A268-B5056A3D83CA) step1 completed
93+
Optional(36A1DF29-CF82-4706-A268-B5056A3D83CA) step2 completed
94+
Optional(177104F2-15A8-437C-8114-69C5D88E7C09) step1 completed
95+
Optional(36A1DF29-CF82-4706-A268-B5056A3D83CA) step3 completed
96+
Optional(177104F2-15A8-437C-8114-69C5D88E7C09) step2 completed
97+
Optional(CA2DA6F3-DAA8-4F2A-AEBE-B5A6357723BF) step1 completed
98+
Optional(177104F2-15A8-437C-8114-69C5D88E7C09) step3 completed
99+
Optional(CA2DA6F3-DAA8-4F2A-AEBE-B5A6357723BF) step2 completed
100+
Optional(CA2DA6F3-DAA8-4F2A-AEBE-B5A6357723BF) step3 completed
101+
```
102+
103+
Each task gets its own `workflowID`, making it easy to correlate logs and trace execution flow—especially useful in debugging and monitoring.
104+
105+
## Conclusion
106+
107+
`TaskLocal` is a powerful tool in Swift’s concurrency toolbox. When used wisely, it can simplify your code by removing the need to pass contextual parameters everywhere.
108+
109+
But like any powerful abstraction, it should be used with care. Make sure you're not hiding too much logic behind implicit context, and use it where it truly improves readability and maintainability.

0 commit comments

Comments
 (0)