Click to see Table of Contents
- Day 1 - First Steps in Swift
- Day 2 - Complex Types
- Day 3 - Operators and Conditions
- Day 4 - Looping
- Day 5 - Functions
- Day 6 - Closures, Part One
- Day 7 - Closures, Part Two
- Day 8 - Structs, Part One
- Day 9 - Structs, Part Two
- Day 10 - Classes
- Day 11 - Protocols And Extensions
- Day 12 - Optionals
- Day 13 - Swift Review, Day One
- Day 14 - Swift Review, Day Two
- Day 15 - Swift Review, Day Three
- Day 16 - Project 1, Part One
- Day 17 - Project 1, Part Two
- Day 18 - Project 1, Part Three
- Day 19 - Unit Conversions Challenge
- Day 20 - Project 2, Part One
- Day 21 - Project 2, Part Two
- Day 22 - Project 2, Part Three
- Days 23 and 24 - Project 3
- Day 25 - MILESTONE: Projects 1-3
- Day 26 - Project 4, Part One
- Day 27 - Project 4, Part Two
- Day 28 - Project 4, Part Three
- Day 29 - Project 5, Part One
- Day 30 - Project 5, Part Two
- Day 31 - Project 5, Part Three
- Day 32 - Project 6, Part One
- Day 33 - Project 6, Part Two
- Day 34 - Project 6, Part Three
- Day 35 - MILESTONE: Projects 4-6
- Day 36 - Project 7, Part One
- Day 37 - Project 7, Part Two
- Day 38 - Project 7, Part Three
- Day 39 - Project 8, Part One
- Day 40 - Project 8, Part Two
- Day 41 - Project 8, Part Three
- Day 42 - Project 8, Part Four
- Day 43 - Project 9, Part One
- Day 44 - Project 9, Part Two
- Day 45 - Project 9, Part Three
- Day 46 - Project 9, Part Four
- Day 47 - MILESTONE: Projects 7-9
- Day 48 - Expanding your horizons
- Day 49 - Project 10, Part One
- Day 50 - Project 10, Part Two
- Day 51 - Project 10, Part Three
- Day 52 - Project 10, Part Four
- Day 53 - Project 11, Part One
- Day 54 - Project 11, Part Two
- Day 55 - Project 11, Part Three
- Day 56 - Project 11, Part Four
- Day 57 - Project 12, Part One
- Day 58 - Project 12, Part Two
- Day 59 - Project 12, Part Three
- Day 60 - MILESTONE: Projects 10-12
- Day 61 - Time for Core Data
- Day 62 - Project 13, Part One
- Day 63 - Project 13, Part Two
- Day 64 - Project 13, Part Three
- Day 65 - Project 13, Part Four
- Day 66 - Project 13, Part Five
- Day 67 - Project 13, Part Six
- Day 68 - Project 14, Part One
- Day 69 - Project 14, Part Two
- Day 70 - Project 14, Part Three
- Day 71 - Project 14, Part Four
- Day 72 - Project 14, Part Five
- Day 73 - Project 14, Part Six
- Day 74 - Project 15, Part One
- Day 75 - Project 15, Part Two
- Day 76 - Project 15, Part Three
- Day 77 - MILESTONE: Projects 13-15
- Day 78 - Time for MapKit
- Day 79 - Project 16, Part One
- Day 80 - Project 16, Part Two
- Day 81 - Project 16, Part Three
- Day 82 - Project 16, Part Four
- Day 83 - Project 16, Part Five
Day 1 - First Steps in Swift
Variables and Constants, Strings, Integers, Doubles and Booleans, Inference and Type Annotations but setting foundations.
Day 2 - Complex Types
Arrays, Sets, Tuples, Dictionaries and Enumerations.
Day 3 - Operators and Conditions
Arithmetic Operators, Operators Overloading, Compound Assignment Operators, Comparison Operators, Conditions, Combining Conditions, The Ternary Operator, Switch Statements and Range Operators.
Day 4 - Looping
For loops, While loops, Repeat loops, Exiting loops, Exiting multiple loops, Skipping items and Infinite loops.
Day 5 - Functions
Writing functions, Accepting parameters, Returning values, Parameter labels, Omitting parameter labels, Default parameters, Variadic functions, Writing throwing functions, Running throwing functions and inout parameters.
Day 6 - Closures, Part One
Creating basic closures, Accepting parameters in a closure, Returning values from a closure, Closures as parameters and Trailing closure syntax.
Day 7 - Closures, Part Two
Using closures as parameters when they accept parameters, Using closures as parameters when they return values, Shorthand parameter names, Closures with multiple parameters, Returning closures from functions and Capturing values.
Day 8 - Structs, Part One
Creating your own structs, Computed properties, Property observers, Methods, Mutating methods, Properties and methods of strings and Properties and methods of arrays.
Day 9 - Structs, Part Two
Initializers, Referring to the current instance, Lazy properties, Static properties and methods and Access control.
Day 10 - Classes
Creating your own classes, Class inheritance, Overriding methods, Final classes, Copying objects, Deinitializers and Mutability.
Day 11 - Protocols And Extensions
Protocols, Protocol inheritance, Extensions, Protocol extensions and Protocol-oriented programming.
Day 12 - Optionals
Handling missing data, Unwrapping optionals, Unwrapping with guard, Force unwrapping, Implicitly unwrapped optionals, Nil coalescing, Optional chaining, Optional try, Failable initializers and Typecasting.
Day 13 - Swift Review, Day One
Variables and Constants, Types of Data, Operators, String Interpolation, Arrays, Dictionaries, Conditional Statements, Loops and Switch Case.
Day 14 - Swift Review, Day Two
Functions, Optionals, Optional Chaining, Enumerations, Structs and Classes.
Day 15 - Swift Review, Day Three
Properties, Static properties and methods, Access control, Polymorphism and typecasting and Closures.
Day 16 - Project 1, Part One
- Creating a form and adding a navigation bar
- Modifying program state:
@State
- Binding state to user interface controls
- Creating views in a loop
Day 17 - Project 1, Part Two
- Reading text from the user with
TextField
- Creating pickers in a form
- Adding a segmented control for tip percentages
- Calculating the total per person
Day 18 - Project 1, Part Three
Challenge
- Add a header to the third section, saying “Amount per person”
- Add another section showing the total amount for the check – i.e., the original amount plus tip value, without dividing by the number of people.
- Change the “Number of people” picker to be a text field, making sure to use the correct keyboard type.
Day 19 - Unit Conversions Challenge
You need to build an app that handles unit conversions: users will select an input unit and an output unit, then enter a value, and see the output of the conversion.
Day 20 - Project 2, Part One
- Using stacks to arrange views
- Colors and frames
- Gradients
- Buttons and images
- Showing alert messages
Day 21 - Project 2, Part Two
- Stacking up buttons
- Showing the player's score with an alert
- Styling our flags
Day 22 - Project 2, Part Three
Challenge
- Add an
@State
property to store the user’s score, modify it when they get an answer right or wrong, then display it in the alert. - Show the player’s current score in a label directly below the flags.
- When someone chooses the wrong flag, tell them their mistake in your alert message.
Challenge
- Create a custom
ViewModifier
(and accompanyingView
extension) that makes a view have a large, blue font suitable for prominent titles in a view. Code - Go back to project 1 and use a conditional modifier to change the total amount text view to red if the user selects a 0% tip. Code
- Go back to project 2 and create a
FlagImage()
view that renders one flag image using the specific set of modifiers we had. Code
Day 25 - MILESTONE: Projects 1-3
Your challenge is to make a brain training game that challenges players to win or lose at rock, paper, scissors.
So, very roughly:
- Each turn of the game the app will randomly pick either rock, paper, or scissors.
- Each turn the app will alternate between prompting the player to win or lose.
- The player must then tap the correct move to win or lose the game.
- If they are correct they score a point; otherwise they lose a point.
- The game ends after 10 questions, at which point their score is shown.
So, if the app chose “Rock” and “Win” the player would need to choose “Paper”, but if the app chose “Rock” and “Lose” the player would need to choose “Scissors”.
Day 26 - Project 4, Part One
- Entering numbers with
Stepper
. - Selecting dates and times with
DatePicker
. - Working with dates.
- Training a model with Create ML.
Day 27 - Project 4, Part Two
- Building a basic layout.
- Connecting SwiftUI to Create ML.
- Cleaning up the user interface.
Day 28 - Project 4, Part Three
- Replace each
VStack
in our form with aSection
, where the text view is the title of the section. Do you prefer this layout or theVStack
layout? It’s your app – you choose! - Replace the “Number of cups” stepper with a
Picker
showing the same range of values. - Change the user interface so that it always shows their recommended bedtime using a nice and large font. You should be able to remove the “Calculate” button entirely.
Day 29 - Project 5, Part One
- Introducing
List
, your best friend - Loading resources from your app bundle
- Working with strings
Day 30 - Project 5, Part Two
- Adding to a list of words
- Running code when our app launches
- Validating words with
UITextChecker
Day 31 - Project 5, Part Three
- Disallow answers that are shorter than three letters or are just our start word.
- Add a toolbar button that calls
startGame()
, so users can restart with a new word whenever they want to. - Put a text view somewhere so you can track and show the player's score for a given root word. How you calculate score is down to you, but something involving number of words and their letter count would be reasonable.
Day 32 - Project 6, Part One
- Creating implicit animations
- Customizing animations in SwiftUI
- Animating bindings
- Creating explicit animations
Day 33 - Project 6, Part Two
- Controlling the animation stack
- Animating gestures
- Showing and hiding views with transitions
- Building custom transitions using ViewModifier
Day 34 - Project 6, Part Three
- When you tap a flag, make it spin around 360 degrees on the Y axis.
- Make the other two buttons fade out to 25% opacity.
- Add a third effect of your choosing to the two flags the user didn't choose.
Day 35 - MILESTONE: Projects 4-6
Your goal is to build an “edutainment” app for kids to help them practice multiplication tables – “what is 7 x 8?” and so on. Edutainment apps are educational at their code, but ideally have enough playfulness about them to make kids want to play.
Breaking it down:
- The player needs to select which multiplication tables they want to practice. This could be pressing buttons, or it could be an “Up to…” stepper, going from 2 to 12.
- The player should be able to select how many questions they want to be asked: 5, 10, or 20.
- You should randomly generate as many questions as they asked for, within the difficulty range they asked for.
Day 36 - Project 7, Part One
- Why
@State
only works with structs - Sharing SwiftUI state with
@StateObject
(baee648
) - Showing and hiding views (
2f08039
) - Deleting items using
onDelete()
(d394d13
) - Storing user settings with
UserDefaults
(01b7a86
) - Archiving Swift objects with
Codable
(6dc754f
)
Day 37 - Project 7, Part Two
- Building a list we can delete from
- Working with
Identifiable
items in SwiftUI - Sharing an observed object with a new view
- Making changes permanent with
UserDefaults
- Final polish (
6578f09
)
Day 38 - Project 7, Part Three
- Use the user’s preferred currency, rather than always using US dollars. (
659659b
) - Modify the expense amounts in
ContentView
to contain some styling depending on their value – expenses under $10 should have one style, expenses under $100 another, and expenses over $100 a third style. What those styles are depend on you. (e4f8c49
) - For a bigger challenge, try splitting the expenses list into two sections: one for personal expenses, and one for business expenses. This is tricky for a few reasons, not least because it means being careful about how items are deleted! (
d8cd46d
)
Day 39 - Project 8, Part One
- Resizing images to fit the screen using
GeometryReader
(6182090
) - How
ScrollView
lets us work with scrolling data (1771dea
) - Pushing new views onto the stack using
NavigationLink
(9daf1a2
) - Working with hierarchical
Codable
data (0781680
) - How to lay out views in a scrolling grid (
7af78aa
)
Day 40 - Project 8, Part Two
- Loading a specific kind of
Codable
data (6717b54
) - Using generics to load any kind of
Codable
data (b38e78e
) - Formatting our mission view (
6619ae8
)
Day 41 - Project 8, Part Three
- Showing mission details with
ScrollView
andGeometryReader
(a345c25
) - Merging
Codable
structs (3d16d9d
) - Finishing up with one last view (
1963dc5
)
Day 42 - Project 8, Part Four
- Add the launch date to
MissionView
, below the mission badge. You might choose to format this differently given that more space is available, but it’s down to you. (6195c6e
) - Extract one or two pieces of view code into their own new SwiftUI views – the horizontal scroll view in
MissionView
is a great candidate, but if you followed my styling then you could also move theRectangle
dividers out too. (6a4d7bc
) - For a tough challenge, add a toolbar item to
ContentView
that toggles between showing missions as a grid and as a list. (c065692
)
Day 43 - Project 9, Part One
- Creating custom paths with SwiftUI (
364ccc2
) - Paths vs shapes in SwiftUI (
e496e0c
) - Adding
strokeBorder()
support withInsettableShape
(8c571e4
)
Day 44 - Project 9, Part Two
- Transforming shapes using
CGAffineTransform
and even-odd fills (b901b77
) - Creative borders and fills using
ImagePaint
(730e153
) - Enabling high-performance Metal rendering with
drawingGroup()
(3a185ae
)
Day 45 - Project 9, Part Three
- Special effects in SwiftUI: blurs, blending, and more (
cf26aeb
) - Animating simple shapes with
animatableData
(618b146
) - Animating complex shapes with
AnimatablePair
(507b626
)
Day 46 - Project 9, Part Four
- Create an
Arrow
shape – having it point straight up is fine. This could be a rectangle/triangle-style arrow, or perhaps three lines, or maybe something else depending on what kind of arrow you want to draw. (5326dfd
) - Make the line thickness of your
Arrow
shape animatable. (18997eb
) - Create a
ColorCyclingRectangle
shape that is the rectangular cousin ofColorCyclingCircle
, allowing us to control the position of the gradient using one or more properties.
Day 47 - MILESTONE: Projects 7-9
Build a habit-tracking app, for folks who want to keep track of how much the do certain things. That might be learning a language, practicing an instrument, exercising, or whatever - they get to decide which activities they add, and track it however they want.
At the very least, this menas there should be a list of all activities they want to track, plus a form to add new activities - a title and description should be enough.
For a bigger challenge, tapping one of the activities should show a detail screen with the description. For a though challenge, make that detail screen contain how many times they have completed it, plus a button incrementing their completion count.
And if you want to make the app really useful, use Codable
and UserDefaults
to load and save all your data.
Day 48 - Expanding Your Horizons
Video - What Star Wars Can Teach Us About Swift
Day 49 - Project 10, Part One
- Adding
Codable
conformance for@Published
properties. (f4d0fbe
) - Sending and receiving
Codable
data withURLSession
and SwiftUI. (0ba3ba1
) - Loading an image from a remote server (
8658089
) - Validating and disabling forms (
6b3aec8
)
Day 50 - Project 10, Part Two
- Taking basic order details. (
c6d3399
) - Checking for a valid address. (
39c8e34
) - Preparing for checkout. (
09f4c96
)
Day 51 - Project 10, Part Three
- Encoding an
ObservableObject
class. (69c4a88
) - Sending and receiving orders over the internet. (
4e8e83d
)
Day 52 - Project 10, Part Four
- Our address fields are currently considered valid if they contain anything, even if it’s just only whitespace. Improve the validation to make sure a string of pure whitespace is invalid. (
bf20e2c
) - If our call to
placeOrder()
fails – for example if there is no internet connection – show an informative alert for the user. To test this, try commenting out therequest.httpMethod = "POST"
line in your code, which should force the request to fail. (5c46e59
) - For a more challenging task, see if you can convert our data model from a class to a struct, then create an
ObservableObject
class wrapper around it that gets passed around. This will result in your class having one@Published
property, which is the data struct inside it, and should make supportingCodable
on the struct much easier. (7053dc9
)
Day 53 - Project 11, Part One
- Creating a custom component with
@Binding
. (d86e4f8
) - Accepting multi-line text input with
TextEditor
. (a11ce3c
) - How to combine Core Data and SwiftUI. (
bc03571
)
Day 54 - Project 11, Part Two
- Creating books with Core Data. (
858dbd0
) - Adding a custom star rating component. (
0067c0d
) - Building a list with
@FetchRequest
. (38fd6ae
)
Day 55 - Project 11, Part Three
- Showing book details. (
c5182b7
) - Sorting fetch requests with
SortDescriptor
. (b428f86
) - Deleting from a Core Data fetch request. (
098397c
) - Using an alert to pop a
NavigationLink
programmatically. (f36e441
)
Day 56 - Project 11, Part Four
Challenge
- Right now it’s possible to select no title, author, or genre for books, which causes a problem for the detail view.
Please fix this, either by forcing defaults, validating the form, or showing a default picture for unknown genres – you can choose.
(
f3cb6e3
) - Modify
ContentView
so that books rated as 1 star are highlighted somehow, such as having their name shown in red. (d3bcc42
) - Add a new “date” attribute to the Book entity, assigning
Date.now
to it so it gets the current date and time, then format that nicely somewhere in DetailView. (18f0ee2
)
Day 57 - Project 12, Part One
- Core Data: Introduction. (
c2922d4
) - Why does
\.self
work forForEach
? (b6be702
) - Creating
NSManagedObject
subclasses. (bf5f11c
) - Conditional saving of
NSManagedObjectContext
. (5e3efc1
) - Ensuring Core Data objects are unique using constraints. (
63740f3
)
- SwiftData: Introduction.
- Editing SwiftData model objects. (
5ae7415
) - Filtering
@Query
using#Predicate
. (ffcce85
)
Day 58 - Project 12, Part Two
- Filtering
@FetchRequest
usingNSPredicate
. (36dd6ae
) - Dynamically filtering
@FetchRequest
with SwiftUI (Basic). (d4050f8
) - Dynamically filtering
@FetchRequest
with SwiftUI (Advanced). (484e794
) - One-to-many relationships with Core Data, SwiftUI, and
@FetchRequest
. (0eac1db
)
- Dynamically sorting and filtering
@Query
with SwiftUI. (c22f126
) - Relationships with SwiftData, SwiftUI, and
@Query
. (1c408b8
) - Syncing SwiftData with CloudKit. (
56b3db0
)
Day 59 - Project 12, Part Three
Challenge
Here are three ways to extend this app by modifying the FilteredList
view:
- Make it accept a string parameter that controls which predicate is applied.
You can use Swift’s string interpolation to place this in the predicate.
(
08c19cc
) - Modify the predicate string parameter to be an enum such as
.beginsWith
, then make that enum get resolved to a string inside the initializer. (2f50b48
) - Make
FilteredList
accept an array ofSortDescriptor
objects to get used in its fetch request. (09f6397
)
- Start by upgrading it to use SwiftData. (
3e03af9
) - Add a customizable sort order option: by name or by amount. (
1149730
) - Add a filter option to show all expenses, just personal expenses, or just business expenses. (
8a85ff8
)
Day 60 - MILESTONE: Projects 10-12
Your job is to use URLSession
to download some JSON from the internet, use Codable
to convert it to Swift types, then use NavigationStack
, List
, and more to display it to the user.
Your first step should be to examine the JSON. The URL you want to use is this: https://www.hackingwithswift.com/samples/friendface.json – that’s a massive collection of randomly generated data for example users.
As you can see, there is an array of people, and each person has an ID, name, age, email address, and more. They also have an array of tag strings, and an array of friends, where each friend has a name and ID. (ae83062
)
Day 61 - Time for Core Data
Challenge
Your job today is to expand your app so that it uses Core Data. Your boss just emailed you to say the app is great, but once the JSON has been fetched they really want it to work offline. This means you need to use Core Data to store the information you download, then use your Core Data entities to display the views you designed – you should only need to fetch the data once. You still need to try to fetch the data every time your app loads, just in case it has changed somehow, but if that fetch fails it’s okay because you still have your Core Data back up.
Day 62 - Project 13, Part One
- How property wrappers become structs.
- Responding to state changes using
onChange()
. - Showing multiple options with
confirmationDialog()
.
Day 63 - Project 13, Part Two
- Integrating Core Image with SwiftUI. (
12d869d
) - Showing empty states with
ContentUnavailableView
. (00a4cda
)
Day 64 - Project 13, Part Three
- Loading photos from the user's photo library. (
6eec33b
) - How to let the user share content with
ShareLink
. (1c5f097
) - How to ask the user to leave an App Store review. (
a8526c3
)
Day 65 - Project 13, Part Four
- Building our basic UI. (
e3631e7
) - Importing an image into SwiftUI using
PhotosPicker
. (642f773
) - Basic image filtering using Core Image. (
fee4949
)
Day 66 - Project 13, Part Five
- Customizing our filter using
confirmationDialog()
. (a4b0ca9
) - Sharing an image using
ShareLink
. (d5271b3
)
Day 67 - Project 13, Part Six
Challenge
- Try making the Slider and Change Filter buttons disabled if there is no image selected.
- Experiment with having more than one slider, to control each of the input keys you care about. For example, you might have one for radius and one for intensity.
Day 68 - Project 14, Part One
- Bucket List: Introduction
- Adding conformance to
Comparable
for custom types (d550513
) - Writing data to the documents directory (
5b6ccb6
) - Switching view states with enums (
52867f4
)
Day 69 - Project 14, Part Two
Day 70 - Project 14, Part Three
- Adding user locations to a map (
a0fec09
) - Improving our map annotations (
22572bc
) - Selecting and editing map annotations (
509c41a
)
Day 71 - Project 14, Part Four
Day 72 - Project 14, Part Five
Day 73 - Project 14, Part Six
Challenge
- Allow the user to switch map modes, between the standard mode and hybrid. (
b115a56
) - Our app silently fails when errors occur during biometric authentication, so add code to show those errors in an
alert. (
cc41a4f
) - Create another view model, this time for
EditView
. What you put in the view model is down to you, but I would recommend leavingdismiss
andonSave
in the view itself - the former uses the environment, which can only be read by the vie, and the latter doesn't really add anything when moved into de model. (dbb0659
)
Day 74 - Project 15, Part One
- Identifying views with useful labels (
e2cc5f4
) - Hiding and grouping accessibility data (
8b3e4d2
) - Reading the value of controls (
0f645bd
)
Day 75 - Project 15, Part Two
Day 76 - Project 15, Part Three
Challenge
- The check out view in Cupcake Corner uses an image and loading spinner that don't add anything to the UI, so find a way to make the screenreader not read them out. (
a1a35e4
) - Fix the list rows in iExpense so they read out the name and value in one single VoiceOver label, and their type in a hint. (
13bf74a
) - Do a full accessibility review of Moonshot - what changes do you need to make so that it's fully accessible? (
58f8af5
)
Day 77 - MILESTONE: Projects 13-15
The goal is to build an app that asks users to import a picture from their photo library, then attach a name to whatever they imported. The full collection of pictures they name should be shown in a List
, and tapping an item in the list should show a detail screen with a larger version of the picture.
Day 78 - Time for MapKit
Continuing with the app built in Milestone: Projects 13-15, now when you’re viewing a picture that was imported, you should show a map with a pin that marks where they were when that picture was added.
Day 79 - Project 16, Part One
Tip
It’s common to want to use NavigationStack
and TabView
at the same time, but you should be careful: TabView
should be the parent view, with the tabs inside it having a NavigationStack
as necessary, rather than the other way around.
Day 80 - Project 16, Part Two
- Understanding Swift’s
Result
type (2427dd8
) - Controlling image interpolation in SwiftUI (
e5368f9
) - Creating context menus (
fbb8c9c
)
Tip
Tips for you when working with context menus, to help ensure you give your users the best experience
- If you’re going to use them, use them in lots of places – it can be frustrating to press and hold on something only to find nothing happens.
- Keep your list of options as short as you can – aim for three or less.
- Don’t repeat options the user can already see elsewhere in your UI.
Remember, context menus are by their nature hidden, so please think twice before hiding important actions in a context menu.
Day 81 - Project 16, Part Three
- Adding custom row swipe actions to a List (
d645ddf
) - Scheduling local notifications (
f25b0a1
) - Adding Swift package dependencies in Xcode (
30349fb
)
Day 82 - Project 16, Part Four
- Building our tab bar (
1bc92b4
) - Storing our data with SwiftData (
6e931b1
) - Dynamically filtering our SwiftData query (
0dcc017
)