Featuring: Fart Button 2: Farts on the Map 🌍💨


Welcome back, master developer! 🧙‍♂️✨ Today we're pushing our skills even further:

  • SQLite
  • Third-party database libraries
  • MapKit integration

All wrapped inside the beautifully absurd Fart Button App, now upgraded to log and map every fart around the world! 🌍🎺💥


📚 What You'll Learn

  • Setting up SQLite manually
  • Using a third-party wrapper (like GRDB or SQLite.swift)
  • Saving and querying custom data
  • Displaying fart locations on a map 🌎💨

🛠 Project Setup

  1. Create a new Xcode project.
  2. Add MapKit.
  3. Install SQLite.swift (or GRDB.swift) using Swift Package Manager:

💾 Why Use SQLite?

  • Blazing fast 🚀
  • Lightweight 📦
  • Cross-platform 🌎
  • Great for apps that don't need full Core Data complexity

You can even inspect your database manually with any SQLite viewer!


💨 Designing the Fart Table

We'll store:

Column Type Description
id Int Primary Key
soundName String The fart sound filename
latitude Double Fart GPS latitude
longitude Double Fart GPS longitude
timestamp Date When it happened

Epic. 🌋


✨ Creating the Fart Database

import SQLite
import MapKit

class FartDatabase {
    static let shared = FartDatabase()
    private var db: Connection?

    let farts = Table("farts")
    let id = Expression<Int64>("id")
    let soundName = Expression<String>("soundName")
    let latitude = Expression<Double>("latitude")
    let longitude = Expression<Double>("longitude")
    let timestamp = Expression<Date>("timestamp")

    private init() {
        do {
            let documentDirectory = try FileManager.default.url(
                for: .documentDirectory,
                in: .userDomainMask,
                appropriateFor: nil,
                create: true
            )
            let fileUrl = documentDirectory.appendingPathComponent("farts").appendingPathExtension("sqlite3")
            db = try Connection(fileUrl.path)

            try db?.run(farts.create(ifNotExists: true) { table in
                table.column(id, primaryKey: true)
                table.column(soundName)
                table.column(latitude)
                table.column(longitude)
                table.column(timestamp)
            })
            print("📦 Database ready!")
        } catch {
            print("😱 Database error: \(error)")
        }
    }

    func addFart(sound: String, coordinate: CLLocationCoordinate2D) {
        let insert = farts.insert(
            soundName <- sound,
            latitude <- coordinate.latitude,
            longitude <- coordinate.longitude,
            timestamp <- Date()
        )
        do {
            try db?.run(insert)
            print("💨 Fart saved!")
        } catch {
            print("😱 Failed to insert fart: \(error)")
        }
    }

    func getAllFarts() -> [(sound: String, location: CLLocationCoordinate2D)] {
        var fartList = [(sound: String, location: CLLocationCoordinate2D)]()
        do {
            for fart in try db!.prepare(farts) {
                let location = CLLocationCoordinate2D(
                    latitude: fart[latitude],
                    longitude: fart[longitude]
                )
                fartList.append((sound: fart[soundName], location: location))
            }
        } catch {
            print("😱 Failed to fetch farts: \(error)")
        }
        return fartList
    }
}

🗺 Building the MapKit UI

import SwiftUI
import MapKit

struct ContentView: View {
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
        span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
    )
    @State private var farts: [(sound: String, location: CLLocationCoordinate2D)] = []

    var body: some View {
        VStack {
            Map(coordinateRegion: $region, annotationItems: farts, annotationContent: { fart in
                MapMarker(coordinate: fart.location, tint: .green)
            })
            .edgesIgnoringSafeArea(.all)

            Button(action: recordFart) {
                Text("💨 Drop a Fart 💨")
                    .font(.title)
                    .padding()
                    .background(Color.green)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .padding()
        }
        .onAppear(perform: loadFarts)
    }

    private func recordFart() {
        let randomOffset = Double.random(in: -0.02...0.02)
        let newCoordinate = CLLocationCoordinate2D(
            latitude: region.center.latitude + randomOffset,
            longitude: region.center.longitude + randomOffset
        )
        FartDatabase.shared.addFart(sound: "RandomFart.mp3", coordinate: newCoordinate)
        loadFarts()
    }

    private func loadFarts() {
        farts = FartDatabase.shared.getAllFarts()
    }
}

Boom. Now every fart is plotted on a map. Historical. 😂


🧠 Key Concepts You Used

  • SQLite database setup 📦
  • Creating and managing tables 🛠
  • Saving records 💾
  • Querying data 🧹
  • MapKit for visualizing 🌍
  • SwiftUI for fun interactions 🧡

🎯 Challenges to Try

  • Add fart categories (Epic, Squeaky, Ninja).
  • Allow fart playback when tapping a pin. 🎧
  • Show a list of recent farts below the map.
  • Save user preferences for fart sounds!
  • Animate fart explosions when a marker is tapped. 💥

You've built the Fart Mapping Revolution! 💨🗺👑

Not only can you save local data with SQLite — you can now map the gaseous trail of glory across the globe. 🌍💚

Keep coding, keep laughing, and keep shipping hilarious apps! 🚀💨