Write Your First MacOS App Using SwiftUI

Developing software for MacOS required a Mac and Xcode. If you don’t have Xcode installed on your Mac, download Xcode and then install it, and then follow these steps.

Set Up the Project

  • Open Xcode and create a new project.
  • Select “App” under the macOS tab.
  • Click “Next” and name your project.
  • Ensure “Swift” is selected as the language and “SwiftUI” for the interface.
  • Click “Next” and choose a location to save your project.

If you select SwiftUI as Interface, you will able to see the output on the right side of the Xcode. You can run the app and it will look like this:

Now let’s build a note-taking app using SwiftUI for MacOS.

Step 1: Create a macOS project in Xcode.

Step 2: Create a Note Model

  1. Create a new Swift file in your project and name it Note.swift.
import Foundation

struct Note: Identifiable, Codable, Hashable {
    var id = UUID()
    var title: String
    var content: String
    var date: Date = Date()
}

We can use some dummy data for testing:

var notes: [Note] = [
    Note(
        title: "Meeting with Team",
        content: "Discuss project roadmap and deliverables for the next quarter. Assign tasks to team members and set deadlines."
    ),
    Note(
        title: "Grocery List",
        content: "Milk, Eggs, Bread, Butter, Cheese, Chicken, Spinach, Tomatoes, Apples, Bananas."
    ),
    Note(
        title: "Workout Plan",
        content: "Monday: Chest and Triceps\nTuesday: Back and Biceps\nWednesday: Rest\nThursday: Shoulders and Abs\nFriday: Legs\nSaturday: Cardio\nSunday: Rest"
    ),
    Note(
        title: "Books to Read",
        content: "1. To Kill a Mockingbird by Harper Lee\n2. 1984 by George Orwell\n3. The Great Gatsby by F. Scott Fitzgerald\n4. The Catcher in the Rye by J.D. Salinger\n5. The Lord of the Rings by J.R.R. Tolkien"
    ),
    Note(
        title: "Vacation Ideas",
        content: "1. Visit Bali, Indonesia for its beautiful beaches and culture.\n2. Explore the historical sites in Rome, Italy.\n3. Experience the Northern Lights in Iceland.\n4. Go on a safari in Kenya.\n5. Relax in the Maldives."
    )
]

Here is the ContentView.swift file:

import SwiftUI

struct ContentView: View {

    @State var notes: [Note] = [
        Note( title: "Meeting with Team",
            content: "Discuss project roadmap and deliverables for the next quarter. Assign tasks to team members and set deadlines." ),
        Note(
            title: "Grocery List",
            content: "Milk, Eggs, Bread, Butter, Cheese, Chicken, Spinach, Tomatoes, Apples, Bananas." )]
    
    @State private var showingAddNoteView = false
    var body: some View {
        NavigationStack {
            List  (notes) { note in
                NavigationLink {
   
                        VStack(alignment: .leading){
                            Text(note.title)
                                .font(.title)
                            Text(note.content)
                        }
                        .padding()
                    
                } label: {
                    VStack(alignment: .leading) {
                        Text(note.title)
                            .font(.headline)
                        Text(note.date.formatted())
                            .font(.subheadline)
                            .foregroundColor(.secondary)
                    }
                }
                
            }
            .navigationTitle("Notes")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button(action: {
                        showingAddNoteView = true
                    }) {
                        Label("Add Note", systemImage: "plus")
                    }
                    .sheet(isPresented: $showingAddNoteView) {
                        AddNoteView(notes: $notes)
                          }
                }
             
            }
        }
    }
}

#Preview {
    ContentView()
}

We have listed notes in a List view. When users click on a Note, they will able to see details of that note.

Now we need a way to add notes. We can add a button to the toolbar to add notes. When users click on the button, they will see an option to add a new note. We can achieve that by using sheets. For that, we will create another view:

struct AddNoteView: View {
    @Environment(\.presentationMode) var presentationMode
    @Binding var notes: [Note]
    @State private var title = ""
    @State private var content = ""

    var body: some View {
        NavigationStack{
            VStack {
                TextField("Title", text: $title)
                TextEditor(text: $content)
                    .padding(5.0)
                    .border(.gray)
                
                HStack(){
                    Button("Cancel") {
                        presentationMode.wrappedValue.dismiss()
                    }
                    Spacer()
                    Button("Save") {
                        notes.append(Note(title: title, content: content))
                        presentationMode.wrappedValue.dismiss()
                    }
                }
            }
            .padding()
            .frame(minWidth: 300, minHeight: 200)
            .navigationTitle("Add Note")
 
        }
    }
}

Here is all the code in one file:

import SwiftUI

struct ContentView: View {

    @State var notes: [Note] = [
        Note( title: "Meeting with Team",
            content: "Discuss project roadmap and deliverables for the next quarter. Assign tasks to team members and set deadlines." ),
        Note(
            title: "Grocery List",
            content: "Milk, Eggs, Bread, Butter, Cheese, Chicken, Spinach, Tomatoes, Apples, Bananas." )]
    
    @State private var showingAddNoteView = false
    var body: some View {
        NavigationStack {
    
            List  (notes) { note in
                NavigationLink {
   
                        VStack(alignment: .leading){
                            Text(note.title)
                                .font(.title)
                            Text(note.content)
                        }
                        .padding()
                    
                } label: {
                    VStack(alignment: .leading) {
                        Text(note.title)
                            .font(.headline)
                        Text(note.date.formatted())
                            .font(.subheadline)
                            .foregroundColor(.secondary)
                    }
                }  
            }
            .navigationTitle("Notes")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button(action: {
                        showingAddNoteView = true
                    }) {
                        Label("Add Note", systemImage: "plus")
                    }
                    .sheet(isPresented: $showingAddNoteView) {
                        AddNoteView(notes: $notes)
                          }
                }
            }
        }
    }
}

#Preview {
    ContentView()
}

struct AddNoteView: View {
    @Environment(\.presentationMode) var presentationMode
    @Binding var notes: [Note]
    @State private var title = ""
    @State private var content = ""

    var body: some View {
        NavigationStack{
            VStack {
                TextField("Title", text: $title)
                TextEditor(text: $content)
                    .padding(5.0)
                    .border(.gray)
                
                HStack(){
                    Button("Cancel") {
                        presentationMode.wrappedValue.dismiss()
                    }
                    Spacer()
                    Button("Save") {
                        notes.append(Note(title: title, content: content))
                        presentationMode.wrappedValue.dismiss()
                    }
                }
            }
            .padding()
            .frame(minWidth: 300, minHeight: 200)
            .navigationTitle("Add Note")
 
        }
    }
}


struct Note: Identifiable, Codable, Hashable {
    var id = UUID()
    var title: String
    var content: String
    var date: Date = Date()
}

You can separate the codes into different files. If you run the project, you will able to see notes in a list. You will also be able to add notes and they will appear in the list.

However, data will be lost if we close the project. For data persistency, we need a way to store data. We can use CoreData, SwiftData, or anything we like.

Leave a Reply