Greetings, traveler!
Swift macros offer a powerful mechanism for code generation, enabling developers to reduce boilerplate and improve clarity. The FoundationModels framework introduces a new macros, designed to streamline data generation for specific model types using language models.
Overview of @Generable
The @Generable
macro can be applied to a Swift struct to indicate that instances of this type may be generated by a language model. When this macro is used, the compiler automatically synthesizes necessary conformances and methods to support streaming responses from a language model session.
@Generable
struct ShoppingItem: Identifiable {
let id: String
let value: String
}
In this example, the ShoppingItem
struct becomes compatible with automatic generation logic provided by the framework. Each instance of ShoppingItem
is expected to be created based on structured output from a language model.
Optionally, a description can be provided to define the context or intent behind the generation:
@Generable(description: "Generate items for a grocery shopping list")
struct ShoppingItem: Identifiable {
let id: String
let value: String
}
This description helps guide the language model toward more accurate results during the generation process.
Using @Guide
for Property-Level Context
For more granular control over how individual properties are interpreted by the language model, the @Guide
macro can be applied to specific properties. This allows developers to provide additional instructions directly related to each property’s expected content.
@Generable(description: "Generate items for a grocery shopping list")
struct ShoppingItem: Identifiable {
let id: String
@Guide(description: "Name of the product to buy")
let value: String
}
Each @Guide
annotation serves as a directive for the language model when generating values for corresponding fields.
Integration in an App
Once a model is marked with @Generable
, it can be used within a LanguageModelSession
to request data. A typical use case involves triggering a generation task in response to user input.
private func generateShoppingList() {
let prompt = "Create 15 shopping list items"
Task {
do {
let session = LanguageModelSession()
let response = session.streamResponse(
generating: [ShoppingItem].self
) {
prompt
}
isGenerating = true
for try await chunk in response {
self.shoppingList = chunk.compactMap {
guard let id = $0.id, let task = $0.value else {
return nil
}
return ShoppingItem(id: id, value: task)
}
}
isGenerating = false
} catch {
print(error.localizedDescription)
isGenerating = false
}
}
}
In this snippet, the streamResponse(generating:prompt:)
method initiates a streaming request for an array of ShoppingItem
instances. As chunks of results arrive, they are processed and appended to the view’s state.
Now, let’s integrate it into our SwiftUI View:
struct ContentView: View {
@State private var shoppingList: [ShoppingItem] = []
@State private var isGenerating: Bool = false
var body: some View {
List(shoppingList) { item in
Text(item.value)
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(
"Generate shopping list",
systemImage: "cart.fill.badge.plus"
) {
generateShoppingList()
}
.disabled(isGenerating)
}
}
}
private func generateShoppingList() {
...
}
}
Conclusion
The @Generable
macro provides a clean and declarative way to integrate language model-based generation into Swift applications. Combined with @Guide
, it offers a structured approach to defining both model-level and field-level expectations for generated data.
If you enjoyed this article, please feel free to follow me on my social media: