Xcode projects and SwiftUI views

What an Xcode project is made of, and how a SwiftUI screen is composed from views and modifiers.

Inside an Xcode project

An Xcode project records targets, build settings and file references. Since Xcode 16 the file that stores that metadata is the folder-based .xcodeproj, which merges far better in version control than the old monolithic project file did.

ItemPurpose
TargetA product to build: the app, a widget, a test bundle
Build settingsCompiler flags, deployment target, bundle identifier, signing
Info.plistDeclared capabilities, usage descriptions, launch configuration
Assets.xcassetsApp icon, accent colour, images with light and dark variants
Swift Package ManagerDependency manager; packages are resolved into the project
SchemeWhich target runs and with what arguments and environment
  • The deployment target is the oldest iOS version that can run the build. API availability annotations let you use newer APIs conditionally.
  • The bundle identifier is permanent for a given app record in App Store Connect — choose it before your first upload.
  • Signing needs a team and a provisioning profile; automatic signing will create and refresh them for you in most cases.

Views and modifiers

In SwiftUI a view is a value that describes part of the screen. The body of a view returns other views, and modifiers wrap a view to change its layout, styling or behaviour.

import SwiftUI

struct Task: Identifiable {
    let id = UUID()
    var title: String
    var isDone: Bool
}

struct TaskRow: View {
    var task: Task

    var body: some View {
        HStack(spacing: 12) {
            Image(systemName: task.isDone ? "checkmark.circle.fill" : "circle")
                .foregroundStyle(task.isDone ? .green : .secondary)
            Text(task.title)
                .strikethrough(task.isDone)
            Spacer()
        }
        .padding(.vertical, 4)
    }
}

#Preview {
    List {
        TaskRow(task: Task(title: "Write the summary", isDone: false))
        TaskRow(task: Task(title: "Ship the build", isDone: true))
    }
}
  • Container views come first: VStack, HStack, ZStack, List, ScrollView, Grid.
  • Modifier order matters: .padding().background(.blue) paints a padded area, while .background(.blue).padding() paints a tight box with space around it.
  • #Preview renders a canvas of the view without running the app — build screens in small previewable pieces.
💡
SwiftUI recomputes body often, so keep it cheap and free of side effects. Never start a network request or mutate state directly in body; use .task or .onAppear for that.

FAQ

What is the difference between a view and a view modifier?
A view describes content; a modifier returns a new view with changed behaviour, layout or appearance. Modifiers are just views wrapped around your content, which is why their order matters.
Why does my preview fail to build?
Commonly because the preview executes real code that expects a network or a database. Inject preview data into the view instead, and keep live services behind a protocol you can stub.

State and navigation Persistence and the App Store

Last refreshed 2026-09-18.