Build a small SwiftUI text feature first: enter a prompt, check that the system model is available, send the request, and show the response or a useful fallback. This route applies when your development tools and the device running the app meet Apple’s current requirements; a successful build alone does not prove the model can run.
Who this is for: Students starting SwiftUI who want to add text generation to a first app.
You can already make a simple screen but aren’t sure how to send a Foundation Models request.
You’re learning on a remote Mac because you don’t have a compatible Mac locally.
This week: Make the page work with sample text, then test a real request only on an environment that passes the runtime availability check.
Last updated September 25, 2026; API and compatibility guidance checked against Apple’s Foundation Models documentation and Xcode system requirements.
Set the first milestone: a page before a model call
Treat this as a small lab exercise, not an AI assistant project. Your first version needs a text field, an action, and a place to show either an answer or a status message. Skip tool calls, images, custom model settings, and agent behavior. They add moving parts before you know whether the basic request works.
Start by checking three separate things:
- Can you develop the app? Confirm that your Mac and Xcode version meet the current requirements listed on Apple’s system requirements page. If you’re using Xcode 27, check the requirements for that exact release rather than assuming it works with every macOS version.
- Can you run the app? Choose a run destination and make sure your practice screen launches there.
- Can that environment run the model? Check availability from the app at runtime. The model’s status depends on the device and its settings, not only on whether the source code compiles.
What should you check before your first request? Confirm Xcode and the running system against Apple’s current requirements, then check the model’s runtime availability on the device you’ll use to test. Apple documents the model access and availability mechanisms; don’t treat a successful build as a substitute for that check.
| Choice | What it lets you verify | What it does not prove | Best next step |
|---|---|---|---|
| Build and run a SwiftUI page with sample text | Your layout, input, button, and visible state changes work | That the system model is available | Add the runtime availability check |
| Run on a simulator | The app can launch in the selected simulated environment | That model inference will work on a physical device or in every simulator setup | Test the model only if availability reports it can run |
| Run on a compatible physical device | The actual device reports its model status and can be tested directly | That another device or a remote Mac has the same status | Record the result for the environment you used |
| Use a remote Mac | You can develop and run your project in the assigned Mac environment | That every remote Mac allocation has model access | Verify the assigned system, Xcode, and runtime status before relying on it |
The key distinction is between development compatibility and model availability. A project can build even when the model is unavailable at runtime. Use Apple’s current SystemLanguageModel availability guidance to make that check inside your app.
Build the page with SwiftUI state
Make the screen prove that input and display work before adding model code. For a beginner, it helps to think of a view as a worksheet and its state as the answers written on it. When state changes, SwiftUI updates the displayed view. Apple explains this relationship in its documentation for SwiftUI state.
Keep the first screen limited to:
- A text field where you enter a question.
- A button that starts the exercise.
- A text area for a sample response, model response, or status.
Use a placeholder response first. Type something harmless, tap the button, and make the screen visibly change. That change might be a status line such as “Request started” or a sample answer such as “Your response will appear here.” You’re checking that the controls are connected—not claiming that a model has answered.
Can you finish the page before the model is ready? Yes. Keep the input, button, and response area in place, and use a clearly labelled sample response or “Model unavailable” message. You can continue learning SwiftUI while you resolve the environment issue; just don’t label sample text as a real model result.
For state, you might start with properties like these inside your view:
@State private var prompt = ""
@State private var answer = ""
@State private var status = "Ready"
Bind prompt to the text field. Update status when the button is tapped, and put answer in the response area. If a state change doesn’t refresh the interface, check that the values you change are actually managed as view state.
Page milestone: You can enter text, trigger an action, and see a visible change. If that fails, fix the view before adding a model session. Otherwise, a broken button and an unavailable model can look like the same problem.
Add one request, not a whole assistant
Once the page works, connect the request. Import FoundationModels, create a LanguageModelSession, and send the user’s prompt with respond(to:). In this exercise, a session is the object that manages a conversation with the model. A prompt is the question you hand it. You don’t need to build a conversation history or add tools to see the first result.
Apple documents LanguageModelSession and the respond(to:) method. Check those pages while coding: API details can change, and the current documentation is the authority for the method signature and behavior.
A deliberately small request flow looks like this:
import FoundationModels
let session = LanguageModelSession()
let response = try await session.respond(to: prompt)
let text = response.content
This is the core of the request, not a complete SwiftUI view. Put it in an asynchronous action, update your view state before and after the request, and handle errors so a failed call doesn’t leave the interface appearing busy.
A beginner-friendly flow is:
- Make sure the prompt isn’t empty.
- Show a status such as “Checking model.”
- Read the current availability.
- If the model is available, show a loading status and send the request.
- Put
response.contentin the answer area, or show a clear error message.
Don’t add more layers until this path works. A response displayed in the app tells you more than a successful compile: it confirms that the button action, asynchronous request, and result display are connected.
Check availability before you decide a request failed
The model’s availability is a runtime condition. Read SystemLanguageModel.default.availability before creating the first request, then present a message that fits the reported state. Apple documents this property in SystemLanguageModel’s availability reference and the reasons an unavailable model can report in its UnavailabilityReason reference.
The documented API shape is:
switch SystemLanguageModel.default.availability {
case .available:
// You can attempt the request.
case .unavailable(let reason):
// Explain the unavailable state to the user.
}
For an unavailable result, use the reason supplied by the API. The documented cases include a device that isn’t eligible, Apple Intelligence not being enabled, and the model not being ready. These are different situations, so don’t report all of them as “your code is broken.” Use the current unavailability reference to confirm the case names and meanings for the SDK you’re using.
Important: Keep your interface honest. If availability says the model can’t run, show the reason or a next step. Don’t keep a spinner running, and don’t display a placeholder as though the model produced it.
A simple fallback policy can be:
- If the device isn’t eligible, let the user keep using the sample-data screen and test real inference on an eligible environment.
- If Apple Intelligence isn’t enabled, explain that it must be enabled before the app can use the model, then let the user retry the availability check.
- If the model isn’t ready, show that it isn’t ready and provide a retry action. Don’t claim that a request succeeded.
- If the request throws an error after availability succeeds, show a request-failed state. Availability and a successful response are separate milestones.
What if the model says unavailable? You can still finish the interface and test its input and status changes. You cannot mark real model inference as complete until an eligible running environment reports availability and returns a response.
Verify each milestone instead of relying on the build result
Use a harmless question with no personal, school, or account information. The point is to check your app’s wiring, not to test sensitive data or judge model quality. Keep a short note of what actually passed.
| Milestone | What you do | What counts as a pass | What to record |
|---|---|---|---|
| Page | Enter text and tap the button | Input and visible UI state change | Page works |
| Availability | Read the system model status in the running app | The app handles the reported status without getting stuck | Available, or the specific unavailable reason |
| Request | Submit a simple prompt when status permits | The asynchronous request completes or returns an error your app handles | Request completed or failed |
| Result | Display the returned content | The screen shows the model response rather than sample text | Real response displayed |
This distinction prevents a common beginner mistake: recording “it works” when only the build or screen passed. A project that compiles has not necessarily checked model availability. A screen that displays a sample answer has not necessarily sent a request. For your course notes, keep those results separate.
How do you continue if you don’t have a local Mac? You can write and refine the SwiftUI screen on another available setup, but a real Foundation Models check requires a running environment that supports the API and reports the model as available. A remote Mac may give you access to macOS development tools, but don’t assume that every allocation meets the model’s conditions. Confirm the actual system and Xcode versions, then run the availability check in that environment.
When a simulator reports unavailable, don’t infer that your app’s request code is wrong—or that every physical device will behave the same way. Use the status from the environment you’re testing, and verify real inference only where the model is available. Keep your framework reference and the runtime status separate in your notes: the first tells you how to call the API, while the second tells you whether the current device can run the model.
Choose your next step from the result
By now, you should know whether you’ve built the page, whether the runtime reports the model as available, and whether the request returned content. Choose the next action based on that evidence:
- The page fails: stay in SwiftUI and fix the input, action, or state display.
- The page works, but the model is unavailable: keep the fallback, record the reported reason, and check the environment or settings before retesting.
- The model is available, but the request fails: inspect the error path and the current
LanguageModelSessionandrespond(to:)documentation. - A real response appears: keep the working text path stable before considering extra features.
Your first milestone is a small, verifiable feature—not an agent. You can add more later, but only after you can distinguish a working screen from a successful model call.
If your current computer blocks the compatibility check, compare the alternatives honestly. A school computer may restrict software installation; a simulator may not prove that real inference is available; and buying a Mac solely for one short course can commit you to a larger purchase before you know what you need. A remote Mac can be a temporary way to test a macOS development environment, but it still may not satisfy Foundation Models requirements. Review VMSPIN’s remote Mac access and current plan details, then confirm the assigned environment’s system, Xcode, and runtime availability before relying on it for your course.