100 Days of SwiftUI
It is May 1st, 2025, and since OpenAI released the 4o Image Generation about a month ago, the Internet has been flooded with images in the style of Studio Ghibli. A bit late to the party, I decided to try it myself, and so was born this post’s thumbnail/hero image.
Now, to the topic: SwiftUI. The idea of multiplatform apps is one that I’ve always had a weird fascination with - it’s just so appealing to write an app once and have it available on multiple platforms, running the same code (mostly). And that’s exactly the promise of SwiftUI or, well, if by multiplatform one means Apple platforms anyway (but who even cares about Windows or Android).
According to Apple, SwiftUI is the best way to build apps across their platforms. Is it, though? I’ve dipped my toes in it and have really enjoyed the developer experience so far. Coming from React and Typescript, Swift and SwiftUI feels like a breath of fresh air, in particular Swift has been a joy - Swift has enjoyable syntax with just enough sugar, is functional but not to the point it gets annoying (cough cough Haskell cough cough), can be concise if one chooses so and has real C interop, oh and enums are actually sensible. It’s not all sunny flower meadows with butterflies and chirping birds, however, with the compiler being absolutely glacial, a lot of key functionality is still AppKit only and Xcode is ummm…not great. But, my biggest gripe is the documentation - let’s just say it’s rather lacking. Because learning a new framework without proper documentation is like trying to build a house without a blueprint, I decided to try the 100 days of SwiftUI course by Paul Hudson. It is a free course aimed at beginners, with the ultimate goal of learning to build apps with Swift and SwiftUI. In this post I will try to document my learnings over the next 100 days.
Days 1-14: Introduction to Swift
First two weeks are an introduction to the Swift programming language. I’m already fairly familiar with Swift, but revisiting the basics never hurt nobody. As expected, I blitzed throught the first two weeks in a couple of days. While most of the content was already familiar, I still did pick up a few things:
-
reversed()
function actually creates aReversedCollection<Self>
- Array method
removeAll()
has a default value and can be called asremoveAll(keepingCapacity: true)
- the former removes all elements and deallocates the storage, while the latter keeps the storage for future use. - copying a function in Swift results in the copy losing the original’s named parameters
Day 15: Consolidation I
Following the introduction to Swift is a repetition round to revise the basics. The urge to skip this day was strong, and I was not strong enough to resist. I did scroll through the material but instead of the suggested one hour, I spent a bit over a minute.
Days 16-24: Starting SwiftUI
This is where the fun begins. Day 16 gives a brief introduction to some SwiftUI components, and on Day 17 we start building our first SwiftUI app - WeSplit, a bill splitting app.
WeSplit
The premise of the app is simple: you enter the cost of the food, select how much of a tip you want to leave (0% in the nordics is the correct answer), and how many people you’re with, and it will tell you how much each person needs to pay. Demo of the final version of the app is below.
UnitConverter
Day 19 is a challenge day where we build a unit converter app. I decided to go with time units, and the app converts between seconds, minutes, hours, days, weeks, months and years. Since it’s just using simple arithmetic, the conversion isn’t particularly accurate, but it’s good enough for this use case where the goal is to just cement the learnings from the first project.
GuessTheFlag
Day 20 starts with the second project - GuessTheFlag. As evident from the name, the app is a game where you guess the flag of a country. The app shows three flags and you have to guess which one belongs to the country shown at the top. The game consists of 8 rounds, after which the score is shown and the user can start a new game.
Views and Modifiers
Days 23 and 24 are about views and modifiers. We learn about ViewBuilders and some tips for composition.
Day 25: Consolidation II
Day 25 is another consolidation day. I did not spend too much time revising the material and instead jumped straight to the challenge. The challenge was to make a brain training game that challenges players to win or lose at rock, paper, scissors. The game is played in 10 rounds, and the score is calculated based on whether the player follows the instructions to win or lose.
Days 26-34: Expanding your skills
The fun continues. This module has three new apps!
BetterRest
Day 26 starts with a new project - an app called BetterRest. The app is a simple form based app that tells the user when they should head to bed in order to get a good night’s sleep. The app uses Core ML to do the prediction, and the model is trained on a dataset of sleep data, using the Create ML app. The UI is brutally simple: a form with a DatePicker, a Stepper and a Picker.
WordScramble
On Day 29 we start yet another project - WordScramble. The game shows the player a random 8-letter word and the goal is to make as many words as possible from the letters. The app is still very simple, but a notable feature is that the words are actually checked using UITextChecker. The word list is a text file that is loaded from the app bundle. Score heuristic is super random: the total character count of the words multiplied by the number of words.
Animations
Animations is another technique project where the goal is to learn, well, animations. In this project we learn about implicit and explicit animations, and how to use them in SwiftUI. Animations in SwiftUI are easy to use and very powerful, and at the same time they really elevate the user experenience to the next level. Day 34 challenge was to add animations to the GuessTheFlag app: clicking a flag rotates it 360 degrees, while the other two are faded out and scaled down slightly.
Day 35: Consolidation III
Day 35 is another consolidation day where our newly acquired skills are put to the test. The challenge is to build an edutaiment app for practicing multiplication tables. Initially the user is presented with a settings screen where they choose if they want 5, 10 or 20 questions. The game keeps track of the score and the final score is shown at the end, as well as a button to start a new game.
I did the bare minimum here, as the app idea is not the most inspiring. The app is functional, but all of the source code is in ContentView.swift
, which is not great.
Days 36-46: Scaling up to bigger apps
In this module we graduate to bigger apps and gradually start to learn how to build real world, complex apps with multiple screens.
iExpense
First app in this module is iExpense, a simple expense tracker. On the surface, it is yet another form based app, but under the hood…it is yet another form based app.

The app itself is still not a complex one by any means, but this is the first app where different views are organized into separate files and the data is passed around. Another notable addition is the use of UserDefaults
to persist a bit of data.
Moonshot
On day 39 we start building project #8 - Moonshot. Moonshot is an app that lets users learn about NASA’s Apollo missions. This is the first app that is somewhat complex, with multiple views and some JSON data parsing. We learn to use LazyVStack
and LazyVGrid
to display the data in a grid or list, and we also learn more about Codable
and how to parse JSON data. Images are displayed with relative size now, thanks to the .containerRelativeFrame()
modifier.
One of the challenges of this project was to add a toggle to switch between the grid and list views, and I snazzed it up a bit by adding custom animations courtery of Claude 4 Sonnet.
Navigation
Navigation is the final “project” in this module, and it is a technical project where we learn about navigation in SwiftUI. We learn about using NavigationLink
with value
and how to manage navigation state using navigationDestination()
and NavigationPath
. Up to this point, all of the navigation was triggered by the user interacting with the UI, but now we have the tools to do it programmatically. For the challenges, we revisited iExpense and Moonshot, with Moonshot getting a central router that handles the navigation between the different views.