Swift Macros
Macros (Swift 5.9+) generate code at compile time. Learn freestanding ( # ) vs attached ( @ ) macros, real examples like #Predicate and @Observable , what they expand to, @attached(member) , SwiftSyntax, and hygiene — you consume far more than you write.
Learn Swift Macros in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Freestanding Macros (#)
Freestanding macros are called with a leading # and act as an expression or declaration on their own. #warning , #file , and #Predicate are common ones.
2️⃣ Attached Macros (@)
Attached macros use a leading @ and decorate a declaration, adding members or conformances. @Observable rewrites a class so SwiftUI can track its changes.
3️⃣ How a Macro Is Declared
A macro declares its role , like @attached(member) , and points to an implementation in a separate target that uses SwiftSyntax to read and emit code.
Your turn. Fill in the freestanding warning macro and the attached observable macro.
📋 Quick Reference
Classify each macro as freestanding or attached, then summarize what a macro expands into and when.
Practice quiz
In which Swift version were macros introduced?
- Swift 5.9
- Swift 4.2
- Swift 5.5
- Swift 5.7
Answer: Swift 5.9. Swift macros arrived in Swift 5.9, alongside Xcode 15.
What syntax marks a freestanding macro at the call site?
- A trailing !
- A => arrow
- A leading # symbol
- A leading @ symbol
Answer: A leading # symbol. Freestanding macros are invoked with a leading # such as #warning or #Predicate.
What syntax marks an attached macro?
- A leading #
- A leading @ symbol
- A trailing ?
- Curly braces
Answer: A leading @ symbol. Attached macros use a leading @ and attach to a declaration, like @Observable.
What does a Swift macro fundamentally do?
- Downloads code
- Runs at app launch
- Replaces the runtime
- Generates and inserts source code at compile time
Answer: Generates and inserts source code at compile time. A macro expands into additional source code that the compiler inserts before type-checking.
The @Observable macro is an example of which kind of macro?
- Attached
- Freestanding expression
- Standalone script
- Runtime reflection
Answer: Attached. @Observable is an attached macro that adds observation conformances to a class.
Which library do you use to read and build syntax trees in a macro implementation?
- Combine
- SwiftSyntax
- UIKit
- Foundation
Answer: SwiftSyntax. Macro implementations operate on syntax trees using the SwiftSyntax library.
What does @attached(member) generate?
- A new file
- A protocol
- A runtime hook
- New members inside the declaration it is attached to
Answer: New members inside the declaration it is attached to. @attached(member) adds new members, such as properties or methods, to the declaration.
Why is macro hygiene important?
- It is decorative
- It speeds up compiling
- Generated names will not accidentally clash with the user's identifiers
- It hides code
Answer: Generated names will not accidentally clash with the user's identifiers. Hygiene ensures introduced identifiers do not collide with names in the surrounding code.
Where does a macro's implementation typically live?
- In the same file inline
- In a separate compiler-plugin package target
- In Info.plist
- In a storyboard
Answer: In a separate compiler-plugin package target. Macro implementations live in a separate macro (compiler-plugin) target, often its own package.
For most developers, the typical relationship with macros is that they...
- Consume far more than they author
- Write many and use few
- Never encounter them
- Only write them
Answer: Consume far more than they author. Most developers use built-in macros like #Predicate and @Observable far more than they write their own.