Tutorials Ultimate SwiftUI Series Chapter 1

Checking Your Tools: Xcode & Your First SwiftUI Project

SwiftUIChapter 1 of the Ultimate SwiftUI Series32 minJune 5, 2026Beginner

Welcome to the Ultimate SwiftUI Series. Before you can build anything, you need a workshop -- and for iOS development, that workshop is Xcode. This first chapter is deliberately unglamorous: you're going to install your tools, make sure they actually run, and learn your way around the room before you start swinging a hammer.

It's tempting to skip the setup chapter and jump straight to building screens. Resist that urge. A few minutes spent learning where things live and which keyboard shortcuts matter will save you hours of fumbling later. Developers who feel fast in Xcode aren't smarter -- they've just internalized the layout and the shortcuts. By the end of this chapter you'll have a working project, you'll know what every pane does, and you'll have run your own app on a simulated iPhone.

What You Need

SwiftUI development happens on a Mac. There's no way around it -- the toolchain, the Simulator, and the SwiftUI preview canvas are all Mac-only.

Why so much disk space?

Xcode bundles the compiler, the debugger, documentation, and platform SDKs for every Apple platform. On top of that, each simulated device you download is its own disk image, and every time you build a project Xcode caches intermediate files. It's normal for a working setup to consume tens of gigabytes over time.

Installing Xcode

Xcode is free. Open the App Store app, search for Xcode, and click Get. It's a large download, so this is a good moment to get a coffee -- on a slower connection it can take a while.

When the download finishes, open Xcode the same way you'd open any Mac app: double-click it in Applications, find it with Spotlight, or click Open from its App Store page. (Later, double-clicking a project's .xcodeproj file will launch Xcode straight into that project.)

The very first launch does some extra work. Xcode ships with macOS support built in, but it needs to download the iOS platform component separately. You'll see a component picker -- select iOS, click Download & Install, and enter your Mac password when prompted. When it finishes, Xcode asks you to relaunch.

First launch is slow -- that's normal

Between the component download and the first time it prepares an iOS Simulator, Xcode does a lot of one-time setup. If it seems to hang on a fresh install, give it a few minutes before assuming something's wrong. This only happens once.

After relaunching, you land on the Welcome to Xcode window. It offers to create a new project, clone an existing one, or open something recent. You can always summon this window again from Window ▸ Welcome to Xcode, or with Shift-Command-1. Every action in that window also has an equivalent in the File menu, so use whichever you prefer.

Creating Your First Project

Let's make a throwaway project to explore. Click Create New Project… in the Welcome window. (The keyboard-only path is Shift-Command-N, or File ▸ New ▸ Project….)

Xcode shows a grid of project templates grouped by platform. You want iOS ▸ App. Select it and click Next.

Now you choose your project's options:

Click Next. Xcode asks where to save the project.

Where did my project go?

If you ever lose track of a project's location, open it and choose File ▸ Show in Finder, or look under File ▸ Open Recent. Xcode remembers everything you've opened lately.

On this save screen there's a Source Control checkbox. If you're saving somewhere that isn't already a Git repository, tick it -- Xcode will initialize a local Git repo for you. Version control from line one is a good habit, and we'll connect this to a remote repository later in the chapter.

Click Create. Your project opens with ContentView.swift showing in the editor, and the iOS Simulator quietly downloading in the background.

That first look at Xcode can be overwhelming -- there are buttons and panels everywhere. Here's the reassuring truth: almost no professional iOS developer knows what every button does. You learn the 20% you use daily, and you look up the rest when you need it. Apple also changes Xcode every year, so "knowing all of it" isn't even a stable target. Let's learn that essential 20% now.

A Tour of the Xcode Window

The Xcode window is organized into three main panes, plus two that appear when you need them:

You can hide or show each pane to reclaim screen space. The toolbar has buttons for the Navigator and Inspectors, the Debug Area has its own toggle, and you can always drag a pane's border to the window edge to collapse it. The shortcuts are worth memorizing on day one:

The Navigator and its nine tabs

The Navigator isn't one list -- it's nine, selectable by the icons across its top bar. When the Navigator is hidden, pressing Command-1 through Command-9 opens it directly to a specific tab. From left to right:

  1. Project -- your files and folders. Add, delete, group, and open files here. This is the tab you'll live in.
  2. Source Control -- Git working copies, branches, commits, tags, remotes, and stashes.
  3. Bookmark -- code landmarks and tasks you've flagged.
  4. Find -- project-wide search and replace.
  5. Issue -- compiler errors and warnings, plus runtime issues.
  6. Test -- create, organize, and run your unit and UI tests.
  7. Debug -- live CPU, memory, disk, and network usage while the app runs.
  8. Breakpoint -- manage all your breakpoints in one place.
  9. Report -- build and run logs you can inspect or export.

At the bottom of each tab is a Filter field, and what it filters depends on the tab. In the Project navigator, for example, it can narrow the list to files you touched recently -- a lifesaver in a project with hundreds of deeply nested files.

The Editor

The Editor is where you'll spend most of your time. For a plain code file it shows your code and, optionally, a Minimap on the right edge -- a zoomed-out overview of the whole file. Hover over the minimap to find a property or method by name, then click to jump there. For the small files in this series you won't need it; hide it from the Adjust Editor Options button at the editor's top-right corner if it's in your way.

For a SwiftUI file, the Editor pairs your code with the preview canvas. Toggle the canvas with Option-Command-Return when you want the full width for code.

The Editor also behaves like a web browser. It has tabs and back/forward history:

The Inspectors

The Inspectors pane shows three to five tabs depending on what you've selected. When it's hidden, Option-Command-1 through Option-Command-5 open it to a specific tab:

  1. File -- name, full path, and target membership of the selected file.
  2. History -- source control and assist logs.
  3. Quick Help -- a compact version of the developer documentation for whatever symbol you've selected in the editor.
  4. Attributes -- the editable properties of the selected symbol.
  5. Accessibility -- accessibility details when you select something in the preview.

Select a file in the Project navigator and all five tabs are available. Select a folder and you get only the first three. Select Assets.xcassets and the Accessibility tab drops off.

A small inconsistency to remember

Option-Command-4 opens the Attributes inspector even though its icon sits after the Accessibility icon in the bar. The shortcut numbers follow the logical order, not the visual one.

Matching Your Navigation Settings

This series uses a few click-to-navigate gestures, and they're configurable -- so let's set yours to match. Press Command-, to open Settings, then choose the Navigation tab and set:

With those set, Command-clicking a symbol jumps you to where it's defined, and Option-clicking pops up its documentation. We'll use both constantly.

Reading ContentView.swift

ContentView.swift is the heart of your fresh project and the file Xcode opened for you. If it's not in front, select it in the Project navigator. The top few lines are auto-generated comments naming the file and its creator -- the compiler ignores them. The real code starts here.

The import statement

import SwiftUI

This line pulls in Apple's entire SwiftUI module so your code can use View, Text, VStack, and everything else SwiftUI provides. It works like imports in most languages: without it, those names simply don't exist.

Want proof it matters? Click anywhere on that line and press Command-/ to comment it out. Xcode immediately lights up with errors complaining that View and Preview are unknown. Press Command-Z to undo and the errors vanish.

Indentation note

Code samples in this series use 2-space indentation to keep things compact. Xcode defaults to 4 spaces. If you'd like to match, change it under Settings ▸ Text Editing ▸ Indentation -- but either works fine.

The ContentView struct

Below the import is a structure -- a named data type that bundles together properties and methods.

struct ContentView: View {
  var body: some View {
    VStack {
      Image(systemName: "globe")
        .imageScale(.large)
        .foregroundStyle(.tint)
      Text("Hello, world!")
    }
    .padding()
  }
}

The struct's name matches the file's name. That's a convention, not a rule -- nothing breaks if they differ -- but everyone follows it, so you should too.

Reading struct ContentView: View, you might assume ContentView inherits from View. It doesn't. Swift structs can't inherit from anything. View is a protocol -- a contract -- and ContentView conforms to it. We'll unpack protocols thoroughly later; for now, "conforms to View" means "promises to behave like a view."

The one thing the View protocol demands is a computed property named body that returns some kind of view. Here, body returns a VStack -- a vertical stack -- that arranges a globe image above a line of text.

Swift tip: implicit return

A computed property hands back the value it computes. When the body is a single expression -- as it is here -- you can omit the return keyword. var body: some View { VStack { … } } is shorthand for return VStack { … }.

Let's name the pieces:

To read a view's documentation, Option-click it. Option-click Text in the editor and a pop-up shows its Quick Help; scroll to the bottom for an Open in Developer Documentation button that opens the full reference. You can also click the Selectable button beneath the canvas, click a view in the preview, and read the same details in the Quick Help inspector.

There's also the Library. Press Shift-Command-L (or click the + in the toolbar) to open it, switch to the Modifiers tab, and scroll to the Text modifiers to browse what's available. The Library closes the moment you click outside it -- unless you hold Option while opening it, which pins it open.

The #Preview macro

Underneath ContentView sits a small but important block:

#Preview {
  ContentView()
}

#Preview is a macro -- shorthand that expands into more code at compile time. Right-click it and choose to expand the macro and you'll see it generate a PreviewRegistry type; that registry is exactly what the canvas renders. Collapse it again with Command-Z.

Curious what happens without it? Select the three #Preview lines and press Command-/ to comment them out. The canvas goes empty -- no preview to register, nothing to show. Uncomment them (Command-/ again, or Command-Z) to bring it back.

When you want maximum room for code, Option-Command-Return hides the canvas; the same shortcut brings it back.

In a real app, ContentView is usually just the starting point. More often than not it does little itself -- it orchestrates several smaller subviews, each defined in its own file. Let's make one.

Creating a Second SwiftUI View

Everything you see on screen in a SwiftUI app is a View. Apple actively encourages you to split your UI into as many small subviews as it takes to stay organized and avoid repetition -- the compiler optimizes it all into efficient machine code, so there's no performance penalty for being tidy.

In the Project navigator, select any file and press Command-N (or right-click and choose New File from Template…). The template chooser appears with a long list of options. The one you want is iOS ▸ User Interface ▸ SwiftUI View.

Select SwiftUI View and click Next. Name the file ByeView -- replacing the default SwiftUIView. By convention the file name matches the view defined inside it.

Swift tip: naming conventions

Swift names types -- structs, classes, enums, protocols -- in UpperCamelCase (ByeView, ContentView). It names properties and methods in lowerCamelCase (body, imageScale). Following this makes your code instantly readable to other Swift developers.

Leave the default location (this project, this group, this target) and click Create. The template for a new SwiftUI view is simpler than ContentView:

import SwiftUI
 
struct ByeView: View {
  var body: some View {
    Text("Hello, World!")
  }
}
 
#Preview {
  ByeView()
}

No image, so no VStack and no padding -- just a single Text. Notice the "Hello, World!" string is highlighted as a token (a placeholder). Click it and type to replace it. Change it to:

Text("Bye bye, World!")

Wiring the new view into ContentView

Now let's use ByeView from ContentView. Open ContentView.swift, delete the Text view inside the VStack, and start typing bye. Xcode's auto-completion offers ByeView -- and notice you didn't even have to capitalize it correctly for Xcode to find it.

Why descriptive names pay off

Auto-completion rewards good naming. The clearer your type and method names, the faster Xcode can suggest the right one and the less you have to type. (You can also enable live spell-checking under Edit ▸ Format ▸ Spelling and Grammar ▸ Check Spelling While Typing.)

Choose ByeView from the suggestions so the line reads:

ByeView()

Those parentheses are you calling the initializer of ByeView -- creating an instance of the view. If the canvas is paused, hit its refresh button, and your custom ByeView now appears where the plain Text used to be. You'll repeat this pattern -- build a small view, then compose it into a larger one -- constantly as you build real apps.

What Else Is in the Project?

The Project navigator lists a handful of files and folders Xcode created for you. Three are worth knowing now.

MyFirstApp.swift -- the entry point

@main
struct MyFirstApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

This file is where your app actually starts. The @main attribute marks MyFirstApp as the launch point. If you've used other languages you might expect to write a main() function by hand -- here, the App protocol handles that for you.

App requires just one thing: a computed property named body that returns a Scene. A scene is a container for a hierarchy of views. For a typical iOS app the default is a WindowGroup holding ContentView() as its root view. On iOS the view hierarchy fills the whole screen; on macOS or iPadOS, a WindowGroup can manage several windows at once. A common real-world tweak is to swap the root view depending on whether the user is signed in.

Assets.xcassets -- images and colors

This is where your app's images and named colors live. AppIcon is a special set holding every size and resolution of your app icon. Since Xcode 14 you can drop in a single 1024×1024 image and let Xcode generate every required size -- just select Single Size in the Attributes inspector.

Preview Content -- development-only assets

Anything your views need only while you're developing -- sample data, placeholder images -- goes here. Assets in Preview Content are excluded from the final build you ship to users.

Don't rename these

Xcode stores the paths to these files and folders in the project's build settings. Rename or delete one and Xcode flags errors because it can no longer find what it expects. Leave the generated structure alone.

Settings Worth Changing Now

Xcode has an enormous Settings window. A few adjustments make day-to-day work noticeably nicer.

Themes

You'll stare at the editor for hours, so make it comfortable. Open Settings (Command-,) and pick the Themes tab. Xcode ships several font-and-color themes; try them out, tweak one, or build your own from scratch. There's no wrong answer -- pick what's easy on your eyes.

Matching delimiters

SwiftUI code nests closures inside closures inside closures, and it's easy to misplace a brace or parenthesis. Xcode helps in a few ways.

Under Settings ▸ Text Editing ▸ Editing, you'll find the code-completion options. Most are genuinely helpful -- and even though you can copy and paste code from this series, typing it yourself is how you learn to feel these aids working. Here's a useful tell: if you expect Xcode to suggest completions and nothing useful shows up, you're probably typing outside the closure you meant to be in.

Now open Settings ▸ Text Editing ▸ Display and enable Code folding ribbon (and Line numbers, if you like them). The code-folding ribbon is the strip of faint gray bars between the line numbers and your code. Hover over one -- say, anywhere between VStack { and .padding() -- and Xcode highlights that closure's opening and closing braces. Click the bar to fold the closure shut, hiding everything inside it; click again to unfold. For navigating deeply nested views, folding is a quiet superpower.

Two more ways to check that your delimiters line up:

Adding Your Accounts

A few Xcode features unlock once you've added account credentials. Open Settings ▸ Accounts and click the + in the lower-left.

Connecting a remote repository

If you ticked Source Control when you created the project, you already have a local Git repo. If not, choose Integrate ▸ New Git Repository… and click Create.

To add a remote: open the Source Control navigator (Command-2), select the Repositories tab, and expand your repository. Right-click Remotes, choose New "MyFirst" Remote…, pick your options, and click Create. Your project now has somewhere to push to.

Running Your App

So far you've only seen the live preview. The canvas is fast and convenient, but some behaviors only work in a full build, and a few only work on a real device. To see your app the way users will, you build and run it on the Simulator.

The toolbar, briefly

A quick orientation to the toolbar, left to right after the Navigator toggle:

You can hide or show the whole toolbar with Option-Command-T.

Choosing a device

Apple sells iPhones and iPads in many sizes, some with a notch or Dynamic Island. How do you know your layout works on all of them without owning every model? You don't need to -- the Simulator runs simulated devices on your Mac.

Click the run destination menu and pick, say, iPhone 16 Pro. The preview canvas uses your run destination by default, so refresh the preview if it's paused and it'll render at that device's size. (You can also force a specific preview device with the previewDevice modifier, and even keep several previews side by side.)

Adding a device that isn't listed

A fresh Xcode install might list only a handful of simulators. To add one -- an older iPhone XR, for example -- click Manage Run Destinations…, choose the Simulators tab, click +, select the model, and click Create. It then shows up in the run destination menu and in the canvas's device picker.

Build and run

Click Run (or press Command-R). The first time you run on a particular simulated device, it boots from cold, so you'll see a loading indicator -- and once it's awake it stays awake until you quit the Simulator app, so later runs skip the startup delay.

After boot, the app's launch screen appears (blank, for MyFirst), and then your app is running. If you open the Debug Area, you can watch live CPU, memory, and other stats in the Debug navigator. There's not much happening in this app yet -- but you built it, and it's running on a simulated iPhone.

The "don't ask again" trick

Here's a small quality-of-life win. Leave the app running -- don't press Stop. Go into ByeView.swift and change the text again:

Text("Hello again, World!")

Press Run (Command-R). Because the app is still running, Xcode pops up a dialog asking whether to stop the current process and run the new one. Before you click Replace, tick Don't ask again, then click Replace.

From now on, hitting Run while the app is already running just relaunches it with your latest code -- no dialog, no interruption. It's a tiny thing you'll appreciate dozens of times a day.

Key Points

In the next chapter, we'll leave setup behind and start prototyping a real screen -- working with images, text, and layout to build something worth looking at.

← Series OverviewCh 2: Planning a Paged App
SwiftUltimate Swift SeriesSwift fundamentals for app developers who want to understand the language behind real iOS and macOS apps.Ship iOSShip iOS Apps SeriesShipping workflows for iOS apps: signing, TestFlight, App Store Connect, CI, and release hygiene.TeardownApp Teardown SeriesApp business and design teardowns covering onboarding, paywalls, ASO, retention, and monetization.

Ship your apps faster

When you're ready to publish your Swift app to the App Store, Simple App Shipper handles metadata, screenshots, TestFlight, and submissions — all in one place.

Try Simple App Shipper
5 free articles remainingSubscribe for unlimited access