DEV Community

Anis Ali Khan
Anis Ali Khan

Posted on • Edited on

Tutorial 1: Build Your First iPhone App – The Fart Button

Welcome, future Apple developer! 🎉

Today, we’re going to create an iPhone app that plays a hilariously unnecessary sound when you press a button: a fart. Because if you can build a fart app, you can build just about anything. (Probably.)

By the end of this tutorial, you’ll:

✅ Set up Xcode and create a new project.
✅ Design a simple UI with a button.
✅ Write Swift code to play a sound.
✅ Laugh at your own creation.

Step 1: Install Xcode

If you haven’t already, install Xcode from the Mac App Store. It’s free, but it’s also huge, so grab a coffee while it downloads. ☕

Verify Xcode Installation

Open Terminal (Cmd + Space, type “Terminal”) and run:

xcode-select --install
Enter fullscreen mode Exit fullscreen mode

If you see “command line tools are already installed”, you’re good to go. If not, follow the prompts.

Step 2: Create a New Xcode Project

  1. Open Xcode.
  2. Click “Create a new Xcode project”.
  3. Select App under iOS and hit Next.
  4. Set the project name to FartButtonApp.
  5. Choose Swift as the language and SwiftUI as the UI framework.
  6. Keep everything else as default and click Finish.
  7. Xcode might ask where to save—pick a folder (like Desktop/FartButtonApp).

🚀 Boom! You’ve officially started your first iOS project!

Step 3: Build the UI

Your app needs one thing: a giant Fart Button.

  1. Open ContentView.swift.
  2. Replace the existing code with:
// Import the SwiftUI framework — this gives us access to everything needed
// to build user interfaces on Apple platforms using declarative syntax.
import SwiftUI

// Define a structure called ContentView that conforms to the View protocol.
// In SwiftUI, every screen or UI component is defined as a "View".
struct ContentView: View {

    // The body property describes what the view looks like.
    // SwiftUI uses this body to render everything on screen.
    var body: some View {

        // VStack (Vertical Stack) arranges its child views vertically (top to bottom).
        VStack {

            // This creates a button that performs an action when tapped.
            Button(action: {
                // This closure runs when the button is pressed.
                // For now, it simply prints a message to the console.
                // (We’ll replace this later with code to play a fart sound!)
                print("Button pressed! Prepare for laughs.")
            }) {
                // The label of the button — what appears visually on screen.
                // Here we’re using a Text view displaying an emoji and phrase.
                Text("Fart")
                    // Make the text large and fun!
                    .font(.largeTitle)
                    // Add space inside the button around the text.
                    .padding()
                    // Set the button’s background color to red.
                    .background(Color.red)
                    // Change the text color to white for contrast.
                    .foregroundColor(.white)
                    // Clip the button shape into a capsule (rounded pill shape).
                    .clipShape(Capsule())
            }
        }
    }
}

// #Preview is a special SwiftUI macro that lets us preview the view live
// in Xcode’s canvas without running the full app in a simulator.
// It’s super useful for visual development and quick iterations.
#Preview {
    ContentView()
}
Enter fullscreen mode Exit fullscreen mode

What’s Happening?

  • The VStack (vertical stack) centers the button.
  • The Button triggers an action when tapped.
  • The button says “Fart”, because obviously.
  • background(Color.red).clipShape(Capsule()) makes it look nice.

🛠 Run the App by pressing Cmd + R. The button doesn’t do anything yet, but you’ve got a working UI!

Step 4: Add the Fart Sound

Now for the science: playing audio in Swift.

Step 4.1: Add a Sound File

  1. Download a fart sound (Example Sound).
  2. Drag the .mp3 file into Xcode’s Assets folder (inside the FartButtonApp project).

💡 Rename it “fart.mp3” to keep things simple.

Step 4.2: Import AVFoundation

Modify ContentView.swift to play a sound:

// Simple Fart Button app using SwiftUI for the UI and AVFoundation for audio playback.
// The comments below explain why each block exists and what it's responsible for.
import SwiftUI
import AVFoundation  // AVFoundation provides AVAudioPlayer which we use to play the fart sound.

// The main view of the app. It shows a single button that, when tapped, plays a sound.
struct ContentView: View {
    // Holds the audio player instance used to play the sound.
    // It's optional because initialization can fail (e.g., missing resource), and the player
    // may be nil at times. In a more feature-complete app you might make this a @State
    // property so the UI can react to changes; here we keep it simple and mutable-only.
    var audioPlayer: AVAudioPlayer?

    // The SwiftUI view hierarchy. This defines what the user sees.
    var body: some View {
        VStack {
            // A button is used here as the primary interaction: tapping it triggers sound playback.
            Button(action: {
                // Delegate the playback work to a separate function to keep UI code clean.
                playFartSound()
            }) {
                // Visual styling for the button: big label, padding, background, and capsule shape.
                Text("Fart")
                    .font(.largeTitle)
                    .padding()
                    .background(Color.red)
                    .foregroundColor(.white)
                    .clipShape(Capsule())
            }
        }
    }

    // Function responsible for locating the audio file in the app bundle, creating an
    // AVAudioPlayer, and starting playback. Keeping this logic in its own function
    // separates concerns (UI vs audio logic) and makes the code easier to read and test.
    func playFartSound() {
        // Find the sound file in the app bundle. If it can't be found we log and return.
        guard let path = Bundle.main.path(forResource: "fart", ofType: "mp3") else {
            // Helpful runtime message for debugging when the resource is missing.
            print("Fart sound not found! 💩")
            return
        }
        // Convert the file path to a URL which AVAudioPlayer expects.
        let url = URL(fileURLWithPath: path)

        do {
            // Initialize the AVAudioPlayer with the file URL. This may throw, so use try.
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            // Start playback. We do not manage playback state here (pause/stop); this is
            // intentionally minimal for a simple tutorial/demo app.
            audioPlayer?.play()
        } catch {
            // If initialization or playback fails, print the localized error for debugging.
            print("Error playing sound: \(error.localizedDescription)")
        }
    }
}

// SwiftUI preview provider — used by Xcode's canvas for a live preview of the view.
#Preview {
    ContentView()
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Run and Enjoy!

  1. Press Cmd + R to run the app.
  2. Tap the “Fart” button.
  3. If everything works, your phone will now make a magnificent noise. 🎉

Step 6: Integrate Game Center for a Fart Leaderboard

Step 6.1: Enable Game Center in Xcode

  1. Go to Signing & Capabilities in Xcode.
  2. Click ”+ Capability” and add Game Center.
  3. In the Apple Developer Console, navigate to App Store Connect → My Apps → Your App.
  4. Go to the Game Center section and create a new leaderboard:
  5. Name: “Most Farts in a Day”
  6. Score Format: Integer
  7. Sort Order: High to Low (because more farts = more glory)
  8. Leaderboard ID: "fart.leaderboard"

Step 6.2: Authenticate the Player

Game Center requires authentication. Modify ContentView.swift:

// Here we define a SwiftUI view that lets the user play a sound, increment their score, and integrate with Game Center leaderboards.

import SwiftUI       // For building the user interface
import AVFoundation  // For audio playback (playing the fart sound)
import GameKit       // For Game Center features like authentication and leaderboards

// The main view for the app's UI and logic
struct ContentView: View {
    // Keeps track of how many times the fart button was pressed
    @State private var fartCount = 0
    // Holds the local Game Center player instance
    @State private var localPlayer = GKLocalPlayer.local

    // Handles audio playback for the fart sound
    var audioPlayer: AVAudioPlayer?

    // The visual hierarchy of the view
    var body: some View {
        VStack {
            // Button for playing the fart sound and updating the score
            Button(action: {
                playFartSound()      // Play sound
                fartCount += 1      // Increment counter
                submitScore()       // Submit score to leaderboard
            }) {
                Text("Fart")
                    .font(.largeTitle)
                    .padding()
                    .background(Color.red)
                    .foregroundColor(.white)
                    .clipShape(Capsule())
            }

            // Displays the total number of farts (score)
            Text("Total Farts: \(fartCount)")
                .font(.title)
                .padding()

            // Button to show the Game Center leaderboard
            Button("Show Leaderboard") {
                showLeaderboard()
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .clipShape(Capsule())
        }
        // Authenticate the user with Game Center when the view appears
        .onAppear {
            authenticatePlayer()
        }
    }

    // Plays the fart sound using AVAudioPlayer
    func playFartSound() {
        // Get path to the fart.mp3 sound file in the app bundle
        guard let path = Bundle.main.path(forResource: "fart", ofType: "mp3") else {
            print("Fart sound not found! 💩")
            return
        }
        let url = URL(fileURLWithPath: path)

        do {
            // Initialize and play the audio
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            audioPlayer?.play()
        } catch {
            // Handle error if audio can't play
            print("Error playing sound: \(error.localizedDescription)")
        }
    }

    // Authenticates the local user with Game Center
    func authenticatePlayer() {
        localPlayer.authenticateHandler = { vc, error in
            if let vc = vc {
                // Present authentication UI if needed
                if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                    scene.windows.first?.rootViewController?.present(vc, animated: true)
                }
            } else if localPlayer.isAuthenticated {
                // Authentication successful
                print("Game Center authenticated: \(localPlayer.displayName)")
            } else {
                // Authentication failed
                print("Game Center authentication failed: \(error?.localizedDescription ?? \"Unknown error\")")
            }
        }
    }

    // Submits the current fart count as a score to Game Center leaderboard
    func submitScore() {
        // Only submit if the player is authenticated
        guard localPlayer.isAuthenticated else {
            print("Player not authenticated")
            return
        }
        // Create a score object for the leaderboard
        let score = GKScore(leaderboardIdentifier: "fart.leaderboard")
        score.value = Int64(fartCount)  // Set score value
        // Submit score to Game Center
        GKLeaderboard.submitScore(score.value, context: 0, player: localPlayer, leaderboardIDs: ["fart.leaderboard"]) { error in
            if let error = error {
                print("Error submitting score: \(error.localizedDescription)")
            } else {
                print("Score submitted: \(score.value)")
            }
        }
    }

    // Presents the Game Center leaderboard UI
    func showLeaderboard() {
        let viewController = GKGameCenterViewController(leaderboardID: "fart.leaderboard", playerScope: .global, timeScope: .allTime)
        // Assign a delegate to handle dismissal
        viewController.gameCenterDelegate = UIApplication.shared.delegate as? any GKGameCenterControllerDelegate

        // Present the leaderboard
        if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
            scene.windows.first?.rootViewController?.present(viewController, animated: true)
        }
    }
}

// SwiftUI preview for ContentView, lets you see the UI in Xcode previews
#Preview {
    ContentView()
}
Enter fullscreen mode Exit fullscreen mode

Step 6.3: Run & Test!

  1. Build & Run the app (Cmd + R).
  2. Tap the Fart Button a few times to rack up points.
  3. Press “Show Leaderboard” and see if you can claim the title of World’s Fart Champion. 🏆

Bonus Features: Make It Even Better!

✅ Add Achievements:

  • "First Fart"
  • "10 Farts in a Row"
  • "Ultimate Gas Master (1000 Farts)"

✅ Add Multiplayer Mode:

  • Challenge friends to a “Fart-Off” in real time.

✅ Use CloudKit to Save Scores:

  • Sync scores across devices.

Wrap-Up

🎉 Congratulations! You just built your first iPhone app! 🚀

You learned how to:
✅ Set up Xcode and create a project.
✅ Design a UI with SwiftUI.
✅ Play sound effects with AVFoundation.
✅ Have way too much fun with a silly app.

🎮 Congratulations! You just built an iPhone game with Game Center! 🚀

  • You authenticated a Game Center player.
  • You submitted scores to a leaderboard.
  • You displayed the leaderboard UI.

🔜 Next Up: Tutorial 2 – Building a To-Do List App with SwiftUI and MVVM

Go forth, unleash chaos, and make Apple proud. 🍏💨

Bonus: Add More Features!

✅ Randomize Fart Sounds
Download multiple sound files (fart1.mp3, fart2.mp3, etc.) and modify playFartSound():

let fartSounds = ["fart1.mp3", "fart2.mp3", "fart3.mp3"]
let randomFart = fartSounds.randomElement() ?? "fart1.mp3"
Enter fullscreen mode Exit fullscreen mode

✅ Make the Button Shake
Add a haptic feedback effect when tapped:

UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
Enter fullscreen mode Exit fullscreen mode

✅ Add a Counter
Track how many farts have been played:

@State private var fartCount = 0
Enter fullscreen mode Exit fullscreen mode

✅ Integrate Game Center (because why not?)
Submit “Most Farts in a Day” as a leaderboard stat.

Next Up:

👉 Tutorial 2: Swift Basics: Variables, Constants, and Data Types

💬 What’s next? Share your fart app with friends, upload it to TestFlight, or… you know, get serious and start learning real iOS development. But where’s the fun in that? 😆

Top comments (0)