Andrew Whipple

The most sensational, inspirational, celebrational, muppetational

Things I Learned Building A Silly Little iOS App

Published 03/20/2024

Hello future employers! This is an example of me being a technically engaged member of the profession, in that I spent my week where I was contractually forbidden from having fun during off my off hours (1) working on a little side project.

I love and have used for years a little app called “Highball” for cocktail recipes. It’s very pretty, very simple, and gets the job done! But one thing is annoying about it, and one thing is concerning about it:

  • Annoying: It’s hard to transfer recipes from one person to another, or one device to another
  • Concerning: It’s a side project from the Studio Neat product design company, and is a companion app to some cocktail products they no longer make, so it’s unreasonable to expect that the app will continue to survive future iOS updates

And, I kinda wanted to learn how to make iOS apps. And so I put together a more-or-less functional proof of concept of a cocktail app that is mostly just a worse version of Highball, but with one tool where you can take a photo of a recipe and it’ll use ~~~~~AI~~~~~ to convert the text in the photo and import it into the app (and some extra abilities to export and import recipes.)

It basically works, which is surprising imo, given I probably spent…. let’s say 20 hours total on it, having never written an iOS app before?

main view recipe view

But anyway, for the SEO gods when a future prospective employer searches “Andrew Whipple developer”, here’s some stuff I learned.

Swift

I think I generally like writing Swift code, in a way that suggests I’d probably like writing Typescript. At the most basic level, while I’m very hardcoded into my Python developer brain, I like silly things like brackets, I like let and var, I like it being a typed language but having type inference. None of it is stuff that would make me switch or anything, but it’s generally intuitive and enjoyable. On the flip side, I like snake_case more than camelCase, so Python I have not abandoned you!

But overall, I like Python for its readability and its (by convention) explicitness, so I enjoy the parts of Swift that are readable and (by convention or by language design) explicit.

I really like Swift closure syntax, these make a ton of sense to me.

recipe.ingredients.contains { ingredient in
    ingredient.name.localizedCaseInsensitiveContains(searchText)
}

// as opposed a more python-y way like
recipe.ingredients.contains(lambda ingredient: ingredient.name.localizedCaseInsensitiveContains(searchText))

// yes i know this is me mixing Swift and Python syntax

I theoretically like required named parameters, and the Apple-y way of using parameter names to construct pseudo-sentences out of function calls

// Read this out loud and it more or less is a sentence!
try? jsonString.write(to: tempURL, atomically: true, encoding: .utf8)

some” still breaks my brain. I get it intellectually, but not at all intuitively.

var body: some View {}

I don’t like do/catch, I much prefer Python’s try/except

do {
  try <a thing that throws>
} catch {
  //handle exception
}

//vs

try {
  <a thing that throws>
} except {
  //handle exception
}

And Swift still has the same color of functions thing that Python does, but obviously async/await fits well with my Python brain. .task/Task() though is easier for me to latch onto than the various asyncio.gather() et al that I have to google every time I ever need to use it.

Also, decoder/encoder are way more confusing to me than the python equivalent json handlers; part of this is I’m sure just unfamiliarity, but also my kingdom for whoever made (or will make) the Swift equivalent of Pydantic for automatic data validation and conversion.

SwiftUI (+ iOS)

My brain does not fundamentally get declarative code (yet.) I can tell because I have a View for a recipe card that currently looks like this:

import SwiftUI

struct CardView: View {
    let recipe: Recipe

    private func ingredientChip(_ ingredient: String) -> some View {
        Text(ingredient)
            .padding(5)
            .foregroundColor(.secondary)
            .background(Color.secondary.opacity(0.2))
            .cornerRadius(5)
    }

    private func getIngredientChips(ingredients: [Ingredient]) -> some View {
        let possibleIngredients = ["Rum", "Vodka", "Gin", "Tequila", "Mezcal", "Whisky", "Whiskey", "Scotch", "Rye", "Bourbon"]

        var presentIngredients = [String]()

        for ingredient in possibleIngredients {
            let filteredIngredients = ingredients.filter { $0.name.localizedCaseInsensitiveContains(ingredient)}
            if !filteredIngredients.isEmpty {
                presentIngredients.append(ingredient)
            }
        }

        let result = HStack {
            ForEach(presentIngredients, id: \.self) { ingredient in
                ingredientChip(ingredient)
            }
        }

        return result
    }

    var body: some View {
        VStack(alignment: .leading) {
            Text(recipe.name).font(.headline)
            Spacer()
            getIngredientChips(ingredients: recipe.ingredients) // this is bad
            .font(.caption)
        }
        .padding()
    }
}

And I know that I’m chucking in this random imperative bit with getIngredientChips(), and I’m sure there’s a declarative way to do this, but this is just where my brain goes first. To get from zero -> working, I think in imperative, and declarative comes later (if at all.)

Related to this, I am happy that this project has shown I have enough basic programming knowledge to be able to sense when it feels like I’m doing things the wrong way. For instance, I’d been trying to have the LLM Model loaded on app startup in the background, but accessed several views deep in the screen for editing an individual recipe. What works is passing it down from the App -> RecipesView -> DetailView -> DetailEditView, but that feels gross, so I strongly believe there’s a better way to do it (and did figure out a way to do it with @EnvironmentObject; maybe still not the right way, but at least feels better.) But I feel good that it feels gross, that implies I have some learned instincts!

I still don’t really get the difference between @State, @StateObject, and @Binding.

The use of enums all over the place is interesting.

Text(ingredient)
  .padding(5)
  .foregroundColor(.secondary) // note the .secondary enum
  .background(Color.secondary.opacity(0.2))
  .cornerRadius(5)

I think I like it, re: the earlier point about how I like readability and explicitness. That said, being new to SwiftUI and iOS frameworks, I have no intuition or knowledge about what those enums will be and where they’ll show up (though Xcode is tolerable for code completion suggestions on that front.)

And overall—aforementioned fact that my brain works in imperative aside—I think SwiftUI looks like a fantastic way to get from zero -> functional in terms of design, and definitely faster than any of my previous half-hearted attempts over the past decade to learn UIKit + MVC patterns.

It seems much much much more difficult to get from functional to good (let alone great) unless you are committed to making your app just look like an Apple sample app. I’ve heard through podcasts with real iOS developers that there are some hard and fast limits to things you can do with SwiftUI, and it’s not fully-featured enough for a complex production app without having to dip into UIKit, but I haven’t experienced that (outside of some file handling/VisionKit stuff, but nothing actually UI related.)

However, my app is very simple, and has no custom style yet, so I’m a terrible test case!

Also lol I have no idea how to do tests in Swift or iOS or SwiftUI. So I didn’t!

AI (as a pair programmer)

I ended up using AI a lot in two different ways on this mini project: one is as a pair programmer (/fancy google) to help guide and build stuff, which I’ll talk about here!

I started playing around with ChatGPT et al probably 3 months ago, and started (in my work context) using Copilot autocomplete and Amazon Q a bit for VSCode. For this, I’m working directly in Xcode, so I’m not accessing Copilot or Q (plus I think my Q access is through my work account.) So in this case, I’ve mostly been using the free version ChatGPT with a bit of a test of Claude, and using their chat interfaces.

Also, in a work context, I’m mostly working on things I understand pretty well at this point (using Python to write endpoints for FastAPI and Django apps) so I fall out to ChatGPT et al about as often as I would’ve fallen out to Google (and even still, I’ll usually send the same query to vanilla google and ChatGPT/Q.)

In this case, I’m new to iOS and Swift! So I used ChatGPT a ton!

As I’ve compared notes with coworkers, I’ve found this use of AI chat tools for coding to be most useful in contexts where:

  • I already know how to do a thing, I just don’t want to do it manually (“convert this if/else block into a switch statement” or “fill out this enum” or the equivalent)
  • I already know how to do a thing in another context, but don’t know how to do it here (“What’s the Django equivalent of some SQL statement?” or “What’s the mongoengine equivalent of some Django query?”)
  • I know what I want done but don’t know how to do it, and I don’t care (or can’t tell) if the results are good

I ran into a couple cases of the first two (“How do I format the string for a double without any decimal points in swift?” or “Make this codable (a big class that I don’t want to write out the coding keys for).” But most of this project has involved the 3rd: I have no compunctions, cares, or even ability to tell whether I’m writing good Swift, I just want to write working Swift!

To that end, a key element of #3 is that it needs to be something I can verify immediately, which is where Swift being a compiled language is nice; it’ll crash out at the build phase when (and yes when, not if, lol) ChatGPT gets something wrong. I generally find then if I just give ChatGPT the error string, it’ll figure it out. Whether it figures out the right or best solution, I can’t tell, but usually gets to working.

In contrast, I find I cannot really use ChatGPT et al for any sizable amount of Python code because I have too high standards for any Python code that goes out with my name on the commit. And it is frequently (again, to my style preferences) bad. In particular, it’s overly verbose and overly twisty in its logic and control flow. The “AIs are your army of junior programmers” quip seems to hold true, because for Python I do think it bears a striking similarity to the work I would’ve done as a junior developer. Which I guess same as above, where this has been an ego boost proving to myself I do have some legitimate programming instincts, I now get the opportunity to cringe at the equivalent of what I would’ve written years ago. Or, the opportunity to cringe at the Swift I am currently writing, because I assume it is bad and amateurish and I don’t care!

Similarly, I am not a good front-end developer, and so I like using ChatGPT at work for simple front-ends to internal tools. It is clunky, bad, not scalable, but:

  • I can’t immediately tell like I can with Python, so it doesn’t offend me in the same way, and
  • it’s fair game for internal tools where working > good. Unacceptable for actual customer-facing code, but fit for purpose there.

So yeah, overall ChatGPT has been a helpful companion as an on-demand Swift/SwiftUI/iOS tutor.

I’ve also re-confirmed in this experience that as I get older I’ve lost the patience to learn via working through a sample project; I’ve tried for years off and on learning Swift and iOS via tutorials and sample projects, and I always get bored because it’s not solving a problem I actually care about solving. Whereas here I feel like I’ve learned a lot, and I’ve had the motivation to continue because I want to make my own thing better.

To that, some of Apple’s instructional material has been very useful, and I got the basic UI shell running by following an unrelated Apple tutorial, but picking and choosing which lessons to follow and swapping in all of their sample app details (in their case a Scrum Meeting timer) with stuff for my cocktail app. Once I got past that point, that’s where ChatGPT became the most useful, again as more or less an on-demand tutor I could ask for instructions on specific challenges as I encountered them.

To that end, I do feel like I learned a reasonable amount, and that’s probably because I went step by step. If I had asked ChatGPT for a whole app skeleton, then nothing would stick, but by asking for each step individually I got the opportunity to actually learn how, for example, PhotoPicker works.

But it was also dumb and bad

That said, a major gigantic whiff was using ChatGPT for any instructions on how to download, convert, and embed a small LLM into my app bundle for use in the image -> recipe parsing.

I spent probably 5-6 hours going in circles as ChatGPT gave me instructions for things that would fail, hallucinated libraries that didn’t exist, gave me instructions for libraries that had breaking changes a year ago, and so on. I tried Claude as an alternative to see if it would be better, and it gave me different guidance and suggestions, but equally wrong ones.

Eventually I had enough examples to figure out the right terms to google and find some Apple documentation that lead to some sample code I was able to read and copy out that eventually worked well enough. But what a total fail on the AI assistant front.

I have some sympathy because LLM tools (currently) are specifically bad at following fast-moving things because they don’t “learn” much after their training cutoff, and AI development is very very fast-moving. So this is a worst-case scenario for the current models. That said, it was massively frustrating, especially in contrast to what a (relatively) useful tool they were on the iOS and SwiftUI front.

AI (as a thing to include in the app)

A lot of talk in the last two weeks in the Apple press has been about how Apple is behind the eight-ball on AI in general, and specifically with how AI integrates into Siri, with the AI-powered Siri features being disastrously behind schedule compared to their public announcements last year.

While that’s damning in terms of highlighting dysfunction between Apple’s marketing and engineering teams, to me the way bigger black mark is that Apple has (kinda by accident) built phones and devices with chips that are incredibly well suited to running AI models locally, and yet it is so difficult to figure out how to do that, and then actually do it in any sort of practical way.

As much as I’m frustrated at ChatGPT and Claude for leading me in circles around how to do this, if I take a step back I’m more frustrated at Apple. As it stands now it sure seems like LLMs themselves veer towards being commodities, where it’s pretty easy for other model developers to catch up to the state of the art (in part because Facebook and Deepseek are very invested in making them open-source commodities.) Apple, however, has a lead in chip performance for devices, millions of devices already out in the world, a huge amount of distribution and platform ownership advantages, and a brand that’s all about privacy and security.

So to my outside eye it looks like the natural “unfair advantage” they could pursue is leveraging their killer hardware, distribution quasi-monopolies, and brand promise to say to developers that iOS is the best platform for them to deploy local AI. I find it hard to believe that Apple will be able to make a better integrated LLM assistant than, say, Google, but I find it very easy to believe that Apple could make a much more attractive developer platform for integrating AI into 3rd party apps than Google ever could.

And yet!!!!!!! How is there not an easy-to-find developer doc saying “Here’s how you do it!”? How is it that I was only able to figure out a way to do it by eventually finding my way to a library that is clearly just a research project, then to the example repo linked from that library (which the example repo for some reason had the actual packages I needed to install), and then to sample code that actually showed me what to do?

And that isn’t even what I actually I wanted to do: my goal was to download a model to my Mac, get it into whatever format Apple needed, bundle it into my application bundle, and ship the model with the application. Ideally I’d love to fine tune it or quantize it or something along the way. Instead the only approach that ended up working was using the Apple research library to download a version of llama on app startup (which takes a about 90-120 seconds, and the app needs to be open in the foreground the whole time) and then store that in what I believe is temporary storage on the device. And of course, the app sometimes crashes because it uses too much memory trying to load this far-too-big-for-purpose full-fledged LLM (and I assume would fully crash out if I wasn’t using an iPhone 15 Pro Max.)

I fully agree with John Siracusa in this week’s episode of Upgrade that the real solution Apple should do is have system APIs that plug into central Apple-provided AI and LLM capabilities that run locally, rather than requiring every app ship a model with its app bundle. But until you do that, it should at least be well-documented how to do the alternative!!!!!!

As it stands now, based on my experience with this little demo app, the best way for an iOS developer to integrate AI into their products is absolutely to get an OpenAI api key and send every request over the network. The fact that that’s the best solution when Apple has the best consumer-grade AI hardware and, again, a brand promise focused on privacy and security is ludicrous.

And especially when it stands in contrast to Apple’s earlier AI features (branded under “ML” lol.) It was 6 hours of work and a bunch of custom code to get to a pseudo-solution for my problem of “How do I parse the freeform text of a recipe into a structured Recipe object?.”

What about “how do I read the text from a user’s photo?” 10 minutes of good Apple documentation and 30 lines of code, mostly just error handling.

import Vision
import UIKit

func recognizeText(from image: UIImage, completion: @escaping (String?) -> Void) {
    guard let cgImage = image.cgImage else {
        completion(nil)
        return
    }

    let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
    let request = VNRecognizeTextRequest { request, error in
        guard let results = request.results as? [VNRecognizedTextObservation] else {
            completion(nil)
            return
        }

        let recognizedText = results.compactMap { $0.topCandidates(1).first?.string }.joined(separator: "\n")
        completion(recognizedText)
    }

    do {
        try requestHandler.perform([request])
    } catch {
        print("Error performing OCR: \(error)")
        completion(nil)
    }
}

“Ask an LLM to pull some structured text out of this freeform text” and “Ask an ML model to pull text out of this photo” are similar questions that should have similar APIs, and I have less than zero complaints about how Apple handles the latter. It felt like magic to be able to add that feature in 10 minutes of work! And it’s absolutely to your benefit as a developer platform to give people that magical feeling as often as you can.

I did not have that feeling working with the LLM.

If this does ever become a real app I release, I’m absolutely pivoting it to the “Just use OpenAI (or Claude or whatever) over the network” approach.

Anyway, rant aside, what I’m actually doing is using MLX to load llama 3.2, certainly overkill for my case, but of the models in the MLX model registry only that, Gemma 2, and Phi 3.5 had anything close to a reasonable balance of workable results and not immediately crashing out due to memory or other installation issues. I tried loading it at app startup and tried loading only when I’m on the Edit view where it can be triggered, and the latter was way worse for performance (basically killing the app if I loaded two Edit views within the same session.) This does mean my app uses way too much memory for normal “just browsing recipes” use, again why if this ever becomes a real app I’ll switch to offloading the LLM stuff to a 3rd party service.

I found it worked much better both in terms of real performance and perceived performance to split the recipe parsing into 3 discrete steps: one to grab the name, one to grab the ingredients, one to grab the instructions (and show a progress bar as it goes through each step) vs trying to fetch the full structured JSON of a recipe.

import Foundation
import MLX
import MLXLLM
import MLXLMCommon

class RecipeParser: ObservableObject {
    private var modelContainer: ModelContainer?

    @Published var loaded: Bool = false

    let maxTokens = 1000

    init() async throws {
        loaded = false
        print("Initializing parser")
        let modelConfiguration = ModelRegistry.llama3_2_3B_4bit
        do {
            self.modelContainer = try await LLMModelFactory.shared.loadContainer(configuration: modelConfiguration)
            loaded = true
            print("Model loaded")
        } catch {
            print("Error loading model")
        }
    }

    private func generate(systemPrompt: String, prompt: String) async throws -> String {
        if loaded {
            let result = try await modelContainer!.perform { context in
                let input = try await context.processor.prepare(
                    input: .init(
                        messages: [
                            ["role": "system", "content": systemPrompt],
                            ["role": "user", "content": prompt],
                        ]))
                return try MLXLMCommon.generate(
                    input: input, parameters: GenerateParameters(), context: context
                ) { tokens in
                    //print(context.tokenizer.decode(tokens: tokens))
                    if tokens.count >= maxTokens {
                        return .stop
                    } else {
                        return .more
                    }

                }
            }
            return result.output
        }
        return ""
    }


    func parseName(recipeText: String) async throws -> String {
        let systemPrompt = """
        You are a simple tool to help parse freeform cocktail recipe text into something more structured.

        You will be given text of a recipe. Extract the name of the recipe and return that. Return only the recipe name
        and no other text. Do not return any other commentary other than the recipe name.
        """
        return try await generate(systemPrompt: systemPrompt, prompt: recipeText)

    }

    func parseInstructions(recipeText: String) async throws -> String {
        let systemPrompt = """
        You are a simple tool to help parse freeform cocktail recipe text into something more structured.

        You will be given text of a recipe. Extract the instructions of the recipe and return that. Return only the cocktail instructions
        and no other text.

        As an example "01:52
        76),
        OLD FASHIONED
        2 oz BOURBON
        ¼ oz SIMPLE SYRUP (1:1)
        1 DASH ANGOSTURA BITTERS
        1 DASH ORANGE BITTERS
        Stir the bourbon, simple syrup, and bitters in a mixing glass with ice. Strain into a rocks glass with one large ice cube. Garnish with an orange peel.
        EDIT
        OZ
        ML
        QTY: 1" should return "Stir the bourbon, simple syrup, and bitters in a mixing glass with ice. Strain into a rocks glass with one large ice cube. Garnish with an orange peel."
        and "BLINKER
        EDIT
        42 oz GRENADINE
        1 oz GRAPEFRUIT JUICE
        2 oz RYE
        Shake and strain" should return "Shake and strain"

        Do not return any commentary or explanation other than what is in the provided text. 
        If you can't find any instructions to parse, return nothing.
        """
        return try await generate(systemPrompt: systemPrompt, prompt: recipeText)

    }

    func parseIngredients(recipeText: String) async throws -> [Ingredient] {
        let systemPrompt = """
        You are a simple tool to help parse freeform cocktail recipe text into something more structured.

        You will be given text of a recipe. Extract the ingredients of the recipe and return them in json of the form
          [
              {
                  "name": string,
                  "unit": string,
                  "amount": float
              }
          ]

        Make sure to convert any fractional amounts to a valid float. For example, an ingredient like "1/2 oz of vodka" should be returned as
        {
            "name": "Vodka",
            "unit": "oz",
            "amount": 0.5
        }

        Return only this array of ingredients and make sure it is valid JSON with no comments. Do not provide any additional commentary. 
        If you can't parse, return []
        """

        var ingredients = [Ingredient]()

        let rawIngredientString = try await generate(systemPrompt: systemPrompt, prompt: recipeText)
        let trimmedIngredientString = extractJSONArray(from: rawIngredientString)
        let dataString = "\(trimmedIngredientString)".data(using: .utf8)

        let decoder = JSONDecoder()
        do {
            let partialIngredients: [PartialIngredient] = try decoder.decode([PartialIngredient].self, from: dataString!)

            for partialIngredient in partialIngredients {
                let newIngredient = Ingredient(name: partialIngredient.name, unit: partialIngredient.unit, amount: partialIngredient.amount)
                ingredients.append(newIngredient)
            }
        } catch let decodingError as DecodingError {
            print(decodingError)
        }

        return ingredients

    }

    private func extractJSONArray(from text: String) -> String {
        guard let startIndex = text.firstIndex(of: "["),
              let endIndex = text.lastIndex(of: "]") else {
            return "[]"
        }

        return String(text[startIndex...endIndex])
    }
}

I also found a little bit of prompt engineering went a long way, at least with llama; Phi 3.5 worked well out of the gate, but was more resource intensive than llama, whereas llama worked well for parsing name and instructions, but parsing out ingredients was sketchier until I added examples to the system prompt.

Anyway, these are my learnings turned rant. Overall neat little experiment, I’m sure it’ll be like 6 years before I try to make another iOS app lol.

As a reward for making it through this tome, here is what I think is the best cocktail recipe I ever created(2):

Lost World

(1): also known in the tech industry as being “on-call”

(2): So called because it’s a Last Word formula (equal parts base spirit, sweet liqueur, herbal liqueur, and acid) using the passionfruit and Campari of the Lost Lake cocktail, and because it’s funny to name it after a Jurassic Park sequel.

Oscars 2k24

Published 03/2/2024

Personal Oscars

2023 - 2022 - 2021 - 2020 - 2019 - 2018

Oscies!!!!

Personal first, these are who I would pick if I had the ability to dictatorially force the awards bodies to my personal preferences.

My personal winner is bolded and italicized.

Supporting Actor

  • Austin Butler (Dune Part Two)
  • Tom Hardy (The Bikeriders)
  • Karren Karagulian (Anora)
  • Edward Norton (A Complete Unknown)
  • Jesse Plemons (Civil War)

Supporting Actress

  • Maria Bakalova (The Apprentice)
  • Monica Barbaro (A Complete Unknown)
  • Rebecca Ferguson (Dune Part Two)
  • Ariana Grande (Wicked)
  • Helena Howard (I Saw The TV Glow)

Actor

  • Adrian Brody (The Brutalist)
  • Mike Faist (Challengers)
  • Ralph Fiennes (Conclave)
  • Josh O'Connor (Challengers)
  • Justice Smith (I Saw The TV Glow)

Actress

  • Felicity Jones (The Brutalist)
  • Mikey Madison (Anora)
  • Demi Moore (The Substance)
  • Renata Reinsve (Handling The Undead)
  • Zendaya (Challengers)

Ensemble

  • The Bikeriders
  • Conclave
  • Dune Part Two
  • Furiosa: A Mad Max Saga
  • Saturday Night

Score

  • Volker Bertelmann (Conclave)
  • Daniel Blumberg (The Brutalist)
  • Alex G (I Saw The TV Glow)
  • Trent Reznor, Atticus Ross (Challengers)
  • Alex Somers, Scott Alario (Nickel Boys)

Screenplay

Includes both Adapted and Original

  • Justin Kuritzkes (Challengers)
  • Sean Baker (Anora)
  • Jesse Eisenberg (A Real Pain)
  • Peter Straughan (Conclave)
  • Denis Villeneuve, John Spaihts (Dune Part Two)

Debut Film

Has to be the director's first full-length narrative film, shorts and student films and (generally) TV movies aren't counted against them

  • Jack Begert (Little Death)
  • Thea Hvistendahl (Handling The Undead)
  • Sam and Andy Zuchero (Love Me)

Director

  • Edward Berger (Conclave)
  • Brady Corbet (The Brutalist)
  • Coralie Fargeat (The Substance)
  • Luca Guadignino (Challengers)
  • Denis Villeneuve (Dune Part Two)

Picture

  • Anora
  • The Apprentice
  • The Brutalist
  • Challengers
  • Civil War
  • A Complete Unknown
  • Conclave
  • Dune Part Two
  • Handling The Undead
  • A Real Pain

Real Oscars

Here are my picks for the actual real Oscars that are real! Last year I got 18/23

Original Screenplay

Should Win: Anora

Will Win: Anora

Adapted Screenplay

Should Win: Dune Part Two

Will Win: Conclave

Visual Effects

Should Win: Dune Part Two

Will Win: Dune Part Two

Sound

Should Win: A Complete Unknown

Will Win: Dune Part Two

Live Action Short

Should Win: ¯\(ツ)

Will Win: The Man Who Could Not Remain Silent

Animated Short

Should Win: ¯\(ツ)/¯ ¯\(ツ)

Will Win: Yuck!

Production Design:

Should Win: Conclave

Will Win: Wicked

Original Song

Should Win: El Mal (Emilia Perez)

Will Win: El Mal (Emilia Perez)

Score

Should Win: Conclave

Will Win: The Brutalist

Makeup And Hairstyling

Should Win: The Substance

Will Win: The Subtance

International Feature

Should Win: Emilia Perez (by default, it's the only one I saw)

Will Win: I'm Still Here

Editing

Should Win: Anora

Will Win: Anora

Documentary Short

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: I Am Ready Warden

Documentary Feature

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: No Other Land

Director

Should Win: Brady Corbet (The Brutalist)

Will Win: Sean Baker (Anora)

Costume Design

Should Win: A Complete Unknown

Will Win: Wicked

Cinematography

Should Win: The Brutalist

Will Win: The Brutalist

Animated Feature

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: The Wild Robot

Supporting Actress

Should Win: Ariana Grande (Wicked)

Will Win: Zoe Saldana (Emilia Perez)

Supporting Actor

Should Win: Kieran Culkin (A Real Pain)

Will Win: Kieran Culkin (A Real Pain)

Actress

Should Win: Mikey Madison (Anora)

Will Win: Demi Moore (The Substance)

Actor

Should Win: Ralph Fiennes (Conclave)

Will Win: Timothee Chalamet (A Complete Unknown)

Picture

Should Win: Dune Part Two

Will Win: Anora

2024 In Lists

Published 12/31/2024

This is also available on my newsletter!

A fair warning, this year I basically watched no movies and listened to no music! 🥳

Previous years: 2023 - 2022 - 2021 - 2020 - 2019 - 2017 - 2016 Podcasts - 2016 Albums

Top 10 TV Or Internet Shows I Watched In 2024 (that weren’t all from 2024)

  • 10) Culinary Class Wars (Netflix)
  • 9) the first season of The Traitors US (Peacock)
  • 8) Just One More Watch (Youtube)
  • 7) Foureyes Furniture (Youtube)
  • 6) the first season of Lost (Netflix)
  • 5) American Crime Story: OJ Simpson (Hulu)
  • 4) the 2024 F1 Season
  • 3) Wristwatch Revival (Youtube)
  • 2) the last two seasons of The Wire (Max)
  • 1) the first two seasons of Veronica Mars (Hulu)

Top 10 Theatrical Things I Saw In 2024

  • 10) Life And Trust - Conwell Tower (NYC, NY)
  • 9) Les Démons - Comédie Française (Paris, FR)
  • 8) American Moor - St Stephen's Theater (Philadelphia, PA)
  • 7) Laser Kiwi: Rise Of The Olive - Edinburgh Fringe Festival (Edinburgh, UK)
  • 6) The Comeuppance - Wilma Theater (Philadelphia, PA)
  • 5) Ulysses - Fringe Arts (Philadelphia, PA)
  • 4) My Mother's Funeral: The Show - Edinburgh Fringe Festival (Edinburgh, UK)
  • 3) The Lehman Trilogy - Arden Theater (Philadelphia, PA)
  • 2) Flight - Edinburgh Fringe Festival (Edinburgh, UK)
  • 1) Sleep No More - The McKittrick Hotel (NYC, NY)

Months, Ranked By The Best Play I Saw During Them, In Som-Mai And My Goal To See At Least A Play A Month In 2024

  • 12) April (Macbeth - Quintessance; Philadelphia, PA)
  • 11) February (God of Carnage - Stagecrafters Theater; Philadelphia, PA)
  • 10) October (Tick Tick Boom - Theatre Horizon; Philadelphia, PA)
  • 9) June (Little Bear Ridge Road - Steppenwolf; Chicago, IL)
  • 8) July (Life and Trust - Conwell Tower; NYC, NY)
  • 7) May (Les Démons - Comédie Française; Paris, FR)
  • 6) November (American Moor - St Stephen's Theater; Philadelphia, PA)
  • 5) December (The Comeuppance - Wilma Theater; Philadelphia, PA)
  • 4) September (Ulysses - Fringe Arts; Philadelphia, PA)
  • 3) March (The Lehman Trilogy - Arden Theater; Philadelphia, PA)
  • 2) August (Flight - Edinburgh Fringe Festival; Edinburgh, UK)
  • 1) January (Sleep No More - The McKittrick Hotel; NYC, NY)

Top 5 Most Financially Devastating Hobbies I Participated In In 2024

  • 5) Leathercrafting (new!)
  • 4) Woodworking/guitarmaking
  • 3) Theater-going
  • 2) Theme parks
  • 1) Watch collecting/watch repair (new!)

Top 6 Theme Parks I Visited In 2024

  • 6) Six Flags Great Adventure (Jackson, NJ)
  • 5) Walt Disney Studios (Disneyland Paris; Paris, FR)
  • 4) EPCOT (Walt Disney World; Orlando, FL)
  • 3) Magic Kingdom (Walt Disney World; Orlando, FL)
  • 2) Hollywood Studios (Walt Disney World; Orlando, FL)
  • 1) Disneyland Paris (Disneyland Paris; Paris, FR)

Top 10 Best Theme Park Foods I Had In 2024

  • 10) Orange Slush at Les Vins des Chefs de France (France Pavilion, EPCOT, Walt Disney World, Orlando, FL)
  • 9) plant-based Ronto Wrap at Ronto Roasters (Galaxy's Edge, Hollywood Studios, Walt Disney World, Orlando, FL)
  • 8) Grapefruit Cake + Cobb Salad + Martini Flight at Hollywood Brown Derby (Hollywood Boulevard, Hollywood Studios, Walt Disney World, Orlando, FL)
  • 7) spiked Iced Mint Tea at Spice Road Table Bar (Morocco Pavilion, EPCOT, Walt Disney World, Orlando, FL)
  • 6) Surly Sarlacc + Endorian Fried Chicken Tip Yip at Docking Bay 7 (Galaxy's Edge, Hollywood Studios, Walt Disney World, Orlando, FL)
  • 5) Creepy Clam Flatbread at Pinocchio Village Haus* (Fantasyland, Magic Kingdom, Walt Disney World, Orlando, FL)
  • 4) Cheese Fritters + It Tastes Like Chicken (Because It Is) at Skipper Canteen (Adventureland, Magic Kingdom, Walt Disney World, Orlando, FL)
  • 3) Ube Green Tea Slushie at Cosmic Ray's Starlight Cafe* (Magic Kingdom, Walt Disney World, Orlando, FL)
  • 2) Beverly soda + Suan Mei Tang soda at Club Cool (EPCOT, Walt Disney World, Orlando, FL)
  • 1) literally anything at Jiko (Animal Kingdom Lodge, Animal Kingdom, Walt Disney World, Orlando, FL)

\Mickey's Not So Scary Halloween Party exclusive*

Top 10 Favorite Watches I Purchased Or Received In 2024

  • 10) Zodiac Super Sea Wolf GMT

Zodiac Super Sea Wolf GMT

  • 9) ~1980s Cartier Formula Ferrari

Formula Ferrari

  • 8) Brew Retrograph Relic (Alton Brown Edition)

Brew Retrograph Relic

  • 7) Orient Mako II

Orient Mako II

  • 6) ~1940s Longines Par Avion MA

Longines Par Avion MA

  • 5) ~1970s unknown model white gold plated manual wind Tissot

Tissot

  • 4) ~1990s Ulysse Nardin San Marco GMT

Ulysse Nardin San Marco GMT

  • 3) Erebus Ascent

Erebus Ascent

  • 2) My Grandpa's ~1950s LeCoultre Futurematic

LeCoultre Futurematic

  • 1) Mark Time M5 prototype

Mark Time M5 prototype

The Watch I Probably Wore The Most In 2024

  • 1) Orient Mako II

Top 6 Honorable Mention Albums Of 2024

The Tortured Poets Department - Taylor Swift; Elle - Dagny; Everyone's Getting Involved: A Tribute To Talking Heads' Stop Making Sense - Various Artists; Cowboy Carter - Beyoncé; Obsessed - Morgan Wade; Bleachers - Bleachers; Dive - Twice

Top 1 Concert I Went To In 2024

  • 1) Taylor Swift: The Eras Tour - La Défense (Paris, FR)

Top 10 Albums Of 2024

Also available at my music tracking site thing

  • 10) FOREVER - Charly Bliss
  • 9) The Angels Are Calling - Katie McBride
  • 8) brat - Charli XCX
  • 7) Manning Fireworks - MJ Lenderman
  • 6) We Really Felt Something - Tiny Stills
  • 5) rosie - Rosé
  • 4) The Anthology* - Taylor Swift
  • 3) GNX - Kendrick Lamar
  • 2) brat and it's completely different but also still brat** - Charli XCX
  • 1) Imaginal Disk - Magdelena Bay

\yes I count this as different*

\*also this too*

Top 5 Honorable Mention Restaurants Or Bars I Went To In 2024

Chez Davia (Nice, FR); Lucette Fait des Crepes (Paris, FR); River Twice (Philadelphia, PA); Parc (Philadelphia, PA); Sushi by Bou (Philadelphia, PA)

Top 10 Restaurants Or Bars I Went To In 2024

  • 10) Skipper Canteen (Walt Disney World, Orlando, FL)
  • 9) Nine Bar (Chicago, IL)
  • 8) Elma (Philadelphia, PA)
  • 7) R&D Cocktail Bar (Philadelphia, PA)
  • 6) Le 10 Bar/Le Comptoir General* (Paris, FR)
  • 5) Kensington Quarters (RIP) (Philadelphia, PA)
  • 4) Kalaya (brunch this time) (Philadelphia, PA)
  • 3) The Bamboo Room at Three Dots And A Dash (Chicago, IL)
  • 2) Jiko (Walt Disney World, Orlando, FL)
  • 1) Le Pré Catelan (Paris, FR)

\Combining these two as my "yay the places I loved when studying abroad held up 10 years later!" pick*

Top 5 New (Or New To Me) Podcasts Of 2024

  • 5) Panic World
  • 4) Western Kabuki
  • 3) Hodinkee Radio
  • 2) Money Stuff
  • 1) The Rest Is History

Top 10 Podcasts Of 2024

  • 10) The Ringer F1 Show
  • 9) Fighting In The War Room
  • 8) Podcast The Ride
  • 7) The Ezra Klein Show
  • 6) Lovett Or Leave It
  • 5) Odd Lots
  • 4) Search Engine
  • 3) Accidental Tech Podcast
  • 2) Doughboys
  • 1) Blank Check

Top 3 Honorable Mention Movies Of 2024

Furiosa: A Mad Max Saga; Disney's Animatronics: A Living History; Little Death

Top 5 Movies Not From 2024 That I Saw For The First Time In 2024

  • 5) The Piano
  • 4) Showing Up
  • 3) Millennium Actress
  • 2) Paprika
  • 1) The Last Temptation Of Christ

Top 5 Movies Not From 2024 That I Rewatched In 2024

  • 5) Oppenheimer
  • 4) Asteroid City
  • 3) Fantasia
  • 2) The Shining
  • 1) Scream

Every 2024 Movie I Saw, Ranked

https://letterboxd.com/andrewthewhip/list/2024-ranked/

Top 10 2024 Movies I Didn't See But Want To

  • 10) Jim Henson: Idea Man
  • 9) Kinds Of Kindness
  • 8) Hit Man
  • 7) Evil Does Not Exist
  • 6) Kneecap
  • 5) The Beast
  • 4) Nickel Boys
  • 3) The Brutalist
  • 2) Anora
  • 1) Nosferatu

Top 10 Movies Of 2024

  • 10) Late Night With The Devil
  • 9) Longlegs
  • 8) I Saw The TV Glow
  • 7) Saturday Night
  • 6) The Bikeriders
  • 5) Handling The Undead
  • 4) Conclave
  • 3) Civil War
  • 2) Dune: Part Two
  • 1) Challengers

Oscars 2k23

Published 03/10/2024

Personal Oscars

2022 - 2021 - 2020 - 2019 - 2018

Oscies!!!!

We begin with the personal picks, if I had the power to make my own nominations. I count (generally) based on US theatrical or streaming wide release, which I think only really impacts one movie this year, but we'll see.

My personal winner is bolded and italicized.

Supporting Actor

  • Swann Arlaud (Anatomy Of A Fall)
  • Robert De Niro (Killers Of The Flower Moon)
  • Robert Downey Jr. (Oppenheimer)
  • Tom Hanks (Asteroid City)
  • John Magaro (Past Lives)

Supporting Actress

  • Maya Hawke (Maestro)
  • Kathryn Hunter (Poor Things)
  • Rachel McAdams (Are You There God? It's Me Margaret)
  • Cara Jade Myers (Killers Of The Flower Moon)
  • Tilda Swinton (The Killer)

Actor

  • Ryan Gosling (Barbie)
  • Charles Melton (May December)
  • Cillian Murphy (Oppenheimer)
  • Jason Schwartzman (Asteroid City)
  • Jeffrey Wright (American Fiction)

Actress

  • Lily Gladstone (Killers Of The Flower Moon)
  • Park Ji-min (Return To Seoul)
  • Cailee Spaeny (Priscilla)
  • Emma Stone (Poor Things)
  • Michelle Williams (Showing Up)

Ensemble

  • Asteroid City
  • Barbie
  • How To Blow Up A Pipeline
  • Killers Of The Flower Moon
  • Oppenheimer

Score

  • Jerskin Fendrix (Poor Things)
  • Ludwig Goransson (Oppenheimer)
  • Joe Hisaishi (The Boy And The Heron)
  • Daniel Pemberton (Spider-man: Across The Spider-verse)
  • Robbie Robertson (Killers Of The Flower Moon)

Screenplay

Includes both Adapted and Original

  • Wes Anderson, Roman Coppola (Asteroid City)
  • Kelly Fremon Craig (Are You There God? It's Me Margaret)
  • Matt Johnson, Matthew Miller (Blackberry)
  • Christopher Nolan (Oppenheimer)
  • Eric Roth, Martin Scorcese (Killers Of The Flower Moon)

Debut Film

Has to be the director's first full-length narrative film, shorts and student films and (generally) TV movies aren't counted against them

  • Raine Allen-Miller (Rye Lane)
  • Cord Jefferson (American Fiction)
  • Celine Song (Past Lives)

Director

  • Wes Anderson (Asteroid City)
  • Sofia Coppola (Priscilla)
  • Daniel Goldhaber (How To Blow Up A Pipeline)
  • Christopher Nolan (Oppenheimer)
  • Kelly Reichardt (Showing Up)

Picture

  • Anatomy Of A Fall
  • Asteroid City
  • The Boy And The Heron
  • How To Blow Up A Pipeline
  • Killers Of The Flower Moon
  • Oppenheimer
  • Poor Things
  • Priscilla
  • Return To Seoul
  • Showing Up

Real Oscars

The Oscars are an actual thing that also exists, so here are my picks for that! Last year I got 17/23

Original Screenplay

Should Win: Anatomy Of A Fall

Will Win: Anatomy Of A Fall

Adapted Screenplay

Should Win: Oppenheimer

Will Win: American Fiction

Visual Effects

Should Win: ¯\(ツ)

Will Win: Godzilla Minus One

Sound

Should Win: Oppenheimer

Will Win: Oppenheimer

Live Action Short

Should Win: ¯\(ツ)/¯ ¯\(ツ)

Will Win: The Wonderful Story Of Henry Sugar

Animated Short

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: Letter To A Pig

Production Design:

Should Win: Barbie

Will Win: Poor Things

Original Song

Should Win: I'm Just Ken (Barbie)

Will Win: What Was I Made For? (Barbie)

Score

Should Win: Killers Of The Flower Moon

Will Win: Oppenheimer

Makeup And Hairstyling

Should Win: Oppenheimer

Will Win: Maestro

International Feature

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: The Zone Of Interest

Editing

Should Win: Oppenheimer

Will Win: Oppenheimer

Documentary Short

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: The ABCs of Book Banning

Documentary Feature

Should Win: ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)/¯ ¯\(ツ)

Will Win: 20 Days In Mariupol

Director

Should Win: Christopher Nolan (Oppenheimer)

Will Win: Christopher Nolan (Oppenheimer)

Costume Design

Should Win: Poor Things

Will Win: Poor Things

Cinematography

Should Win: Oppenheimer

Will Win: Oppenheimer

Animated Feature

Should Win: The Boy And The Heron

Will Win: The Boy And The Heron

Supporting Actress

Should Win: probably Da'vine Joy Randolph? I didn't see The Holdovers but I affirmatively think Emily Blunt and America Ferrera should NOT win

Will Win: Da'vine Joy Randolph (The Holdovers)

Supporting Actor

Should Win: Robert De Niro (Killers Of The Flower Moon)

Will Win: Robert Downey Jr. (Oppenheimer)

Actress

Should Win: truly a 50/50 tie between Lily Gladstone (Killers Of The Flower Moon) and Emma Stone (Poor Things)

Will Win: Lily Gladstone (Killers Of The Flower Moon)

Actor

Should Win: Cillian Murphy (Oppenheimer)

Will Win: Cillian Murphy (Oppenheimer)

Picture

Should Win: Oppenheimer

Will Win: Oppenheimer

2023 In Lists

Published 12/31/2023

This is also available on my newsletter!

This year, we're making a LIST, and checking it once, and then hitting publish without really checking for typos.

Previous years: 2022 - 2021 - 2020 - 2019 - 2017 - 2016 Podcasts - 2016 Albums

Top 10 TV Or Internet Shows I Watched In 2023 (that weren’t all from 2023)

  • 10) the first two seasons of The OC (Fox, Hulu)
  • 9) Blacktail Studios (Youtube)
  • 8) the final season of The West Wing (NBC, HBO Max)
  • 7) Drive To Survive (Netflix)
  • 6) The Fall Of The House Of Usher (Netflix)
  • 5) Foureyes Furniture (Youtube)
  • 4) Succession (HBO, HBO Max)
  • 3) the last three seasons of The Sopranos (HBO, HBO Max)
  • 2) Scott Pilgrim Takes Off (Netflix)
  • 1) the first three seasons of The Wire (HBO, HBO Max)

Top 5 Theatrical Things I Saw In 2023

  • 5) Leopoldstadt - Longacre Theater (NYC, NY)
  • 4) The Seagull/Woodstock, NY - Pershing Square Signature Theater (NYC, NY)
  • 3) Lovett or Leave It: The Errors Tour - The Fillmore (Philadelphia, PA)
  • 2) Blank Check: 8th Anniversary Live - The Opera House (Brooklyn, NY)
  • 1) Sleep No More - The McKittrick Hotel (NYC, NY)

Top 10 Honorable Mention Albums Of 2023

The Land Is Inhospitable And So Are We - Mitski; Tomorrow's Fire - Squirrel Flower; Rat Saw God - Wednesday; Psychopath - Morgan Wade; The Answer Is Always, Yes - Alex Lahey

Top 3 Concerts I Went To In 2023

  • 3) Charly Bliss* - Johnny Brendas (Philadelphia, PA)
  • 2) The Gaslight Anthem - Hard Rock Hotel (Atlantic City, NJ)
  • 1) Pet Symmetry - Ukie Club (Philadelphia, PA)

*asterisk, sadly had to leave the concert early so didn't actually see CB 😢

Top 10 Albums Of 2023

Also available at my new music tracking site thing

  • 10) History Books - The Gaslight Anthem
  • 9) Desire, I Want To Turn Into You - Caroline Polachek
  • 8) Scaring The Hoes - Danny Brown, JPEGMAFIA
  • 7) No Joy - Spanish Love Songs
  • 6) The Record - boygenius
  • 5) Guts - Olivia Rodrigo
  • 4) 152 - Taking Back Sunday
  • 3) After The Magic - Parannoul
  • 2) softscars - yeule
  • 1) The Weakness - Ruston Kelly

Top 10 Honorable Mention Restaurants Or Bars I Went To In 2023

Hook & Master (Philadelphia, PA) (RIP); South Philly Barbacoa (Philadelphia, PA); Izakaya By Yanaga (Philadelphia, PA); Empanada Mama (NYC, NY); Ember & Ash (Philadelphia, PA); Gilda (Philadelphia, PA); DwitGolMak (Los Angeles, CA); Southwark (Philadelphia, PA); Ramen Tatsu-ya (Austin, TX); Honey's Sit 'n Eat (Philadelphia, PA)

Top 10 Restaurants Or Bars I Went To In 2023

  • 10) Talula's Garden (Philadelphia, PA)
  • 9) Hav & Mar (NYC, NY)
  • 8) Phocific Standard Time (Seattle, WA)
  • 7) Cassell's (Los Angeles, CA)
  • 6) Blue Bayou (Disneyland, Anaheim, CA)
  • 5) Kalaya (Philadelphia, PA)
  • 4) Tiki Tatsu-ya (Austin, TX)
  • 3) Murph's (Philadelphia, PA)
  • 2) Carthay Circle Lounge (Disney's California Adventure, Anaheim, CA)
  • 1) Trader Sam's Enchanted Tiki Bar (Disneyland, Anaheim, CA)

Top 10 New (Or New To Me) Podcasts Of 2023

  • 10) Fintech Takes
  • 9) WTF1
  • 8) Slate Money
  • 7) Plain English
  • 6) Unhedged
  • 5) Judging Sam
  • 4) U Springin' Springsteen On My Bean?
  • 3) The Ringer F1 Show
  • 2) Popcast: Deluxe
  • 1) Search Engine

Top 10 Podcasts Of 2023

  • 10) The Vergecast
  • 9) Fighting In The War Room
  • 8) Accidental Tech Podcast
  • 7) Podcast The Ride
  • 6) The Ezra Klein Show
  • 5) The Town
  • 4) Odd Lots
  • 3) Lovett Or Leave It
  • 2) Doughboys
  • 1) Blank Check

Top 10 Honorable Mention Movies Of 2023

Maestro; Past Lives; Barbie; Blackberry; The Killer; Scream VI; Master Gardener; Rye Lane; M3GAN; May December

Top 5 Movies Not From 2023 That I Saw For The First Time In 2023

  • 5) The History Of The Seattle Mariners
  • 4) Unforgiven
  • 3) In The Cut
  • 2) JFK
  • 1) Sympathy For Lady Vengeance

Top 5 Movies Not From 2023 That I Rewatched In 2023

  • 5) Heat
  • 4) Stop Making Sense
  • 3) The Empire Strikes Back
  • 2) Toy Story 2
  • 1) The Social Network

Every 2023 Movie I Saw, Ranked

https://letterboxd.com/andrewthewhip/list/2023-ranked/

Top 10 2023 Movies I Didn't See But Want To

  • 10) Wonka
  • 9) Eileen
  • 8) Bottoms
  • 7) Talk To Me
  • 6) Napoleon
  • 5) Skinamarink
  • 4) Ferrari
  • 3) Beau Is Afraid
  • 2) The Zone Of Interest
  • 1) Poor Things

Top 10 Movies Of 2023

  • 10) Anatomy Of A Fall
  • 9) Spider-Man: Across The Spiderverse
  • 8) Air
  • 7) How To Blow Up A Pipeline
  • 6) Priscilla
  • 5) Return To Seoul
  • 4) The Boy And The Heron
  • 3) Oppenheimer
  • 2) Asteroid City
  • 1) Killers Of The Flower Moon

(More posts ➡)