For Day 98, we implemented searching resorts, replaced the facility info with icons, added a button for the user to mark favorite resorts, and added a favorite indicator in the Resorts list. #100DaysOfSwiftUI
For Day 98, we implemented searching resorts, replaced the facility info with icons, added a button for the user to mark favorite resorts, and added a favorite indicator in the Resorts list. #100DaysOfSwiftUI
For Day 97 we started actually building a new project using NavigationSplitView
, NavigationLink
, and format: .list(type: .and)
(for concatenating strings). #100DaysOfSwiftUI
Day 96 and we’re looking at iPad-friendly APIs for the first time.
I’ll be honest—I had not tried running any of our previous apps in the iPad simulator, but now I see they were working fine the whole time. Pretty cool!
This screenshot looks absolutely chaotic. 👹 #100DaysOfSwiftUI
Day 94 is a review and challenge day! Graphics code can be a doozy because when you get the wrong result, it’s difficult to know what’s actually wrong in the code (or with your math). 😅 I got some help with this one. 😬 #100DaysOfSwiftUI
Day 93 was a fun walk through of using GeometryReader
, including using visualEffect()
and scrollTargetBehavior()
. #100DaysOfSwiftUI
For Day 92, we started a new project (our second to last!) and learned about how layout, alignment guides, and absolute positioning work within SwiftUI.
I really loved the explainer, starting from How layout works in SwiftUI. #100DaysOfSwiftUI
Picking #100DaysOfSwiftUI back up, and in the home stretch at Day 91! It was a challenge day with a review quiz and an open-ended prompt to fix a couple minor bugs and add a feature.
For Day 90, we made a bunch of accessibility fixes and added a view for creating new cards! #100DaysOfSwiftUI
For Day 89, we learned how to detect when our app moves to the background or foreground so we could pause and restart our timer at the right moment. #100DaysOfSwiftUI
For Day 88, we built a brand new part of the app with a stack of cards and gestures for swiping them left and right to move to the next card. #100DaysOfSwiftUI
For Day 87, we learned a little bit about the Combine framework, Timer
, and three accessibility settings: Differentiate Without Color, Reduce Motion, and Reduce Transparency. #100DaysOfSwiftUI
For Day 86, we started a brand new project and started playing with all the gesture APIs and hit testing. #100DaysOfSwiftUI
Day 85 is a challenge day! The quiz was easy but the challenge took me about an hour to complete. The “contacted” icon, link to an edit screen, and sort options are all new. #100DaysOfSwiftUI
For Day 84, we learned how to add swipe actions to list items and show local notifications using the UserNotifications
framework! #100DaysOfSwiftUI
Day 83 has this tidbit:
The CPU running our code doesn’t care about data types, comments, access control, and more, but if you want to write great software that is scalable, testable, and maintainable, you need to add some rules.
There’s a little piece of me that wishes we talked more about testing and maintainability. I know they’re more advanced topics that I’ll learn on my own, but a man can still wish.
Today we added UI to scan QR codes and multi-item editing. #100DaysOfSwiftUI
Day 82 was much easier—I don’t think there was anything new, we “just” laid the groundwork for the new tabs and added the SwiftData pieces to store the contact info. #100DaysOfSwiftUI
Today was almost smooth sailing, learning about list row swipe actions and local/scheduled notifications, but I ran into issues with the directions for adding Swift package dependencies in Xcode.
I wrote up the issue and my fix in this issue: Day 81: No such module 'SamplePackage'
#100DaysOfSwiftUI
Day 80 and we’re learning about Result, image interpolation, and context menus.
This stood out to me:
Remember, context menus are by their nature hidden, so please think twice before hiding important actions in a context menu.
Undiscoverable UI might as well be no UI at all. I value explicit UI that’s easy to discover and understand. #100DaysOfSwiftUI
Day 79 and we’re (finally) learning about TabView, my favorite way to keep our example code around!
One actual takeaway from today: impressive that an EditButton can affect the state of a List in the same view without any explicit bindings; I’m usually cautious of “magical” APIs. #100DaysOfSwiftUI
For Day 78, we started saving the user’s current location when they save one of the photos to the app. Easy peasy! #100DaysOfSwiftUI
Day 77 was a doozy of a challenge: build an entire app from scratch that imported a photo, prompted for a name, stored both somehow (I chose SwiftData), display it in a list, and show a detail view.
It was a lot of work but took me about an hour from start to finish. #100DaysOfSwiftUI
For Day 76, we had a quiz and challenge: fix accessibility issues in three of our past apps.
For Cupcake Corner, I couldn’t reproduce the issue.
For iExpense, the fix was easy.
For Moonshot, there were a couple images that needed labels, but I couldn’t find any other issues. #100DaysOfSwiftUI
I liked Paul’s message on Day 75 of #100DaysOfSwiftUI much better:
There’s a New York lawyer called Gregory Mansfield who fights for disability rights, and he once wrote this: “Accessibility is not charity. Accessibility is not generosity. Accessibility is not an amenity. Accessibility is not a gratuity. You don’t bestow access – you ensure it.”
👏
On Day 74 we’ve started learning about accessibility.
I‘m not a fan of how this is framed:
Tony Fadell – the creator of the iPod at Apple – had this to say: “you are defined by what you do and also by what you don’t do.”
Sure, you can skip accessibility and 90% of people won’t notice, but do you want to be defined by that? I’d wager that the answer is no.
I wish this focused on accessibility as a fundamental human right that’s needed by all of us at one point or another… not just an arbitrary percentage (that is really low as well). #100DaysOfSwiftUI
Day 73 was a challenge day, so I had fun refactoring some of the code from the main View into a ViewModel and adding error handling. #100DaysOfSwiftUI
Today we refactored our code to use MVVM and added “unlock with FaceID” to this part of the app.
From Day 72:
Tip: I get lots of questions about why I place my view models into view extensions, […]. This is a small app, but think about how this would look when you have 10 views, or 50 views, or even 500 views. If you use extensions like this, the view model for your current view is always just called ViewModel, and not EditMapLocationViewModel or similar – it’s much shorter, and avoids cluttering up your code with lots of different class names!
Hm, I’m not 100% convinced… #100DaysOfSwiftUI
For Day 71, we used Wikipedia’s API to fetch places near a set of coordinates. I had no idea this was a thing, and I already have an existing app idea that I think could leverage this. #100DaysOfSwiftUI
For Day 70 we added the ability to pin locations on a map and edit them.
We were supposed to use .onLongPressGesture
, but I couldn’t get it to work in the previews or simulator, so I just used another .onTapGesture
. #100DaysOfSwiftUI
Day 69 was short: we learned how to 1) add different types of maps and 2) use Face ID to unlock the app. #100DaysOfSwiftUI
Day 68 has been some of the most interesting content (from a language-learning perspective) in a while.
First, yes the method is just called
<
, which is the “less than” operator. It’s the job of the method to decide whether one user is “less than” (in a sorting sense) another, so we’re adding functionality to an existing operator. This is called operator overloading, and it can be both a blessing and a curse.
I don’t think I’ve ever worked in a language with operator overloading and it definitely makes me nervous about maintainability. #100DaysOfSwiftUI
Day 67 is the last day for this particular project, so we had a review quiz (got 12/12) and added some features to the app without any code prompts, just requirements.
I’m always a little nervous when the challenges are easy… what did I miss? 😅 #100DaysOfSwiftUI
Back at it after a little Thanksgiving break and we’ve run into our first (I think) need to use @MainActor
.
Today we added the ability to change image filters and share the resulting image. #100DaysOfSwiftUI
Day 65 and this sort of thing still gets me:
We can then call that whenever our
selectedItem
property changes, by attaching anonChange()
modifier somewhere inContentView
– it really doesn’t matter where, but attaching it to thePhotosPicker
would seem sensible.
We covered modifiers and building our own much earlier in the course, but I still don’t have a good mental model for how/why you can put some of them anywhere and they’ll work. #100DaysOfSwiftUI
For Day 64 we learned how to use PhotosPicker
to… let the user pick photos, use ShareLink
to… create share links, and call requestReview()
to… request the user leave a review of our app! #100DaysOfSwiftUI
For Day 63, we learned about the different Image APIs available: Image
, UIImage
, CGImage
, and CIImage
. We also tried out ContentUnavailableView
!
I continued my normal practice of keeping all the sample code in the project and building UI to see it all. #100DaysOfSwiftUI
For Day 62, I liked that we were shown “Open Quickly” in Xcode and told how to find the definition of a generated interface. I don’t fully understand it now, but I know I will in a couple years.
Oh, and for the start of a new project, we played around with confirmationDialog()
. #100DaysOfSwiftUI
Nope, today was the hardest challenge.
I thought it was weird that yesterday’s challenge didn’t require us to use SwiftData (when we had just spent a bunch of days working with it).
Day 61, the other shoe drops—we need to rewrite yesterday’s app to use SwiftData. #100DaysOfSwiftUI
I thought yesterday was our most difficult day so far… now Day 60 has surpassed it.
Today we built an app from scratch with just some requirements to fetch data and build a couple views. Straightforward but a lot of work! #100DaysOfSwiftUI
Wow, I’m impressed with myself for learning and SwiftData/SwiftUI for being easy.
For Day 59, we had to go back to an old app and upgrade it to use SwiftData, add sorting, and add filtering. It took me about an hour to do everything, which is a lot faster than I expected. #100DaysOfSwiftUI
Day 58: Continuing yesterday’s project and learning about NSPredicate, changing fetch requests dynamically, and creating relationships. One of today’s sections is about syncing SwiftData with CloudKit, but I skipped it because I don’t have a paid developer account (yet)! #100DaysOfSwiftUI
Starting a new project for Day 57, so don’t have much to show so far. We’re learning how to edit SwiftData objects with SwiftUI and filter data using #Predicate
. #100DaysOfSwiftUI
Day 56 was a review and challenge (on our own) day, so I updated the detail view to handle missing data more gracefully. #100DaysOfSwiftUI
For Day 55 we learned how to delete SwiftData objects, sort queries using SortDescriptor
, and add custom buttons to alerts. #100DaysOfSwiftUI
For Day 54, we earnestly started the implementation of a “Bookworm” app and created new SwiftData models and SwiftUI components.
I think the only new APIs were .constant()
and using .buttonStyle(.plain)
to disable the whole “tap the row to trigger its buttons” behavior. #100DaysOfSwiftUI
Day 53 is the start of our first project with SwiftData. So far all the terminology reminds me of my Core Data days. #100DaysOfSwiftUI
Day 52 is a review quiz and challenge day. I found the challenges pretty easy this time around! #100DaysOfSwiftUI
It’s our first day using the debugger! I love debuggers so much. I feel like teaching how to use real debuggers is undervalued by the developer community.
Day 51, officially over half-way done with #100DaysOfSwiftUI!
Continuing our new project in Day 50 by using CodingKeys
to make @Observable
get along with JSONEncoder().encode()
, and learning about haptics with the .sensoryFeedback()
modifier and CHHapticEngine
. #100DaysOfSwiftUI
New project day! Day 49 was focused on async
/await
, URLSession.shared.data()
, AsyncImage
, and the .disabled()
modifier. I’m continuing to use TabView
so I can keep all the sample code around in a project. #100DaysOfSwiftUI
Day 48 included watching two videos. Paul’s had a fun premise (“What Star Wars Can Teach Us About Swift”) and Woz’s video seemed aimed at high-schoolers, but had some good takeaways: “make your studies… a fun part of life” and “always try to be creative and think different.” #100DaysOfSwiftUI
Day 47 was a review and challenge day, with an entire app we had to build from scratch on our own. I’m stoked it only took me 30 minutes to put together this app! #100DaysOfSwiftUI
Day 46 was a review quiz and a challenge!
Today is the first day I’ve run into this error (that I’ve seen so many SwiftUI developers complain about):
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
Does that make me a real SwiftUI dev now? #100DaysOfSwiftUI
Adding a tab bar wasn’t part of Day 45, but I wanted to keep my other view and start “fresh” with today’s code. We actually went through navigationBarTitleDisplayMode()
, toolbarBackground()
, toolbarColorScheme()
, toolbar()
, ToolbarItem
, and passing bindings to navigationTitle()
. #100DaysOfSwiftUI
For Day 44 I made this abomination while learning the ins and outs of NavigationPath. #100DaysOfSwiftUI
I had been wondering about how to only load detail views when they’re navigated to, and in Day 43 I got my answer! Hello navigationDestination(for:destination:)
👋 #100DaysOfSwiftUI
Day 42 (hey!) is a challenge day and I am taking it easy with just a refactoring of some views and not adding a brand new list view (with a toggle between it and the grid view). 🇺🇸 #100DaysOfSwiftUI
Day 41 was our last day of adding pre-made #100DaysOfSwiftUI code to this Moonshot project. Tomorrow, challenge!
I really appreciate Xcode’s previews. It reminds me of the love I professed for demo files in my CSS-Tricks “modlets” article years ago.
For Day 40 we put into practice what we learned yesterday by starting the implementation of the Moonshot app. Pretty cool that #100DaysOfSwiftUI provides sample data and images to build more interesting-looking apps like this one.
We’re starting a new “Moonshot” project for Day 39 and learning about Image
resizing, LazyVStack
, LazyHStack
, LazyVGrid
, LazyHGrid
, NavigationLink
, and decoding hierarchical data with Codable
.
I wonder about learning optimizations like the Lazy versions of Stack/Grid so early on. #100DaysOfSwiftUI
Day 38 included a quiz and some prompts for us to add features on our own to the app, which included coloring the expense amounts and adding the separate Business/Personal sections (while still keeping support for deleting expenses in those new sections)! #100DaysOfSwiftUI
Day 37, using the APIs we learned yesterday in a new app, but this stood out to me (emphasis mine):
First, we need to decide what an expense is – what do we want it to store? In this instance it will be three things: the name of the item, whether it’s business or personal, and its cost as a
Double
.
In a real app, you should almost always keep prices as integers so math with them is accurate.
As a training creator, I know there’s a trade-off between having “production-ready” code vs. simplifying it for learning.
This is a case where I would have made a different decision. #100DaysOfSwiftUI
Day 36 is the start of a new project, and thus a day of learning new APIs: @Observable
with class
, .sheet()
, @Environment
, .onDelete()
, UserDefaults
/ @AppStorage
, Codable
, and JSONEncoder
.
I would’ve liked more info about @Environment
but I’m sure we’ll get into it more soon. #100DaysOfSwiftUI
I finished the Day 35 challenge today. It’s been a while since I’ve been “challenged” when programming, so this was a great reminder to stay humble while learning something new. #100DaysOfSwiftUI
Yesterday I looked at the Day 35 challenge (build a new app from just a description, no code) and I was like “nope, don’t have the energy today.”
I worked on it for ~45 minutes tonight and started off strong, but I’ve run into some errors that I’ll have to come back to tomorrow. #100DaysOfSwiftUI
Day 34 was a quiz and challenge day where we went back to one of our previous projects and added animations on our own. I really liked the challenge because I wasn’t expecting to go back to a previous project! #100DaysOfSwiftUI
Day 33… continuing with animations and I swear this is more fun than it looks from a single screenshot. #100DaysOfSwiftUI
Yes, I do embrace absolute chaos when I’m first trying the provided sample code so I can keep playing with older examples as I’m learning more intricate modifiers. Day 32 in the books! #100DaysOfSwiftUI
Day 31 was a challenge day where we took a test and had to update our app with only some requirements and no code hints. I extended mine to show a score based on the number of letters in each correct guess. #100DaysOfSwiftUI
Back on it after being sick the last couple days… for day 30, we mostly copied code from the tutorial, but I find it very useful to type everything out to get that muscle memory built up.
Here’s a little game where you have to type words that are a subset of a random word. #100DaysOfSwiftUI
Day 29 is bringing me back to my Objective-C days:
let range = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en")
The full rangeOfMisspelledWordInString:range:startingAt:wrap:language:
API signature is too long for this post. #100DaysOfSwiftUI
Day 28 was straightforward—a review quiz and some challenges for us to modify our most recent app. Onward! #100DaysOfSwiftUI
I realize that you might have thought “wow, we’re looking at machine learning already?” After all, this is only day 27 of a 100-day course. But, as Andre Gide said, “you cannot discover new oceans unless you have the courage to lose sight of the shore.”
Heh, #100DaysOfSwiftUI read my mind!
Today we built a UI on top of the Core ML model we trained yesterday. Straightforward but fun!
I was not expecting “Training a model with Create ML” to be a part of the Day 26 content!
As someone who has built a lot of training content this past year for work, I know how valuable it is to create fun/engaging exercises, so it impresses me to see Machine Learning (ML) in #100DaysOfSwiftUI
Haha this looks so awful, but day 25’s challenge was fun: to build a rock/paper/scissors game from scratch! #100DaysOfSwiftUI
Day 24 was straightforward—a test and a few little changes to make on our own to our recent projects. I had to go back to remember the syntax for custom modifiers. Onward! #100DaysOfSwiftUI
Today I learned that the order of modifiers does matter:
Text("Hello, world!")
.padding()
.background(.red)
.padding()
.background(.blue)
.padding()
.background(.green)
.padding()
.background(.yellow)
Day 23 in the books! #100DaysOfSwiftUI
Day 22 was really easy—added the score counter and a different alert for when the game is “over.” #100DaysOfSwiftUI
Day 21 had us building a mini flag-guessing game, but without the score implemented. I will be absolutely shocked, shocked I say when we implement the score as the next day’s challenge. 🇺🇸 🇺🇦 🇪🇸 #100DaysOfSwiftUI
Day 20 is all about stacks, gradients, buttons, and images. I find it more fun to keep all the sample code in one project and let it pile up. 🤪 #100DaysOfSwiftUI
Day 19, very fun to have a day focused on building a new app from scratch! This was my take on the challenge. #100DaysOfSwiftUI
Day 18 is a short quiz and adding some new code on our own without any guidance—it took so little time (9 minutes 😝) that I’m tempted to just start on the next day, but I will resist! #100DaysOfSwiftUI
This definitely trips me up:
Tip: It’s tempting to think that modifier should be attached to the end of the
NavigationStack
, but it needs to be attached to the end of theForm
instead. The reason is that navigation stacks are capable of showing many views as your program runs, so by attaching the title to the thing inside the navigation stack we’re allowing iOS to change titles freely.
I’m not sure I 100% understand the reasoning here… excited to learn more. It’s still only day 17! #100DaysOfSwiftUI
Day 16, starting off with creating a new iOS app in Xcode and seeing everything that’s changed since I last used it almost 12 years ago. Hitting Run for the first time… ah it’s so exciting! #100DaysOfSwiftUI
Day 15 is a review of the last two weeks of material! #100DaysOfSwiftUI
I kept on going back to the individual pages to find the syntax I needed while working on the tests, so I’m happy to have it all on one page: www.hackingwithswift.com/articles/…
Day 14 is optionals, guards, nil coalescing, optional chaining, and optional try.
Guards are new to me but I like them:
func double(number: Int?) -> Int? {
guard let number = number else {
return nil
}
return number * 2
}
Two weeks in the books! #100DaysOfSwiftUI
Prototypes, opaque return types, extensions, and protocol extensions don’t have equivalents in JavaScript (and my TypeScript isn’t good enough to compare Swift to TS), but these concepts were straightforward enough that I breezed through day 13. #100DaysOfSwiftUI
copies of the same class share their underlying data, meaning that changing one changes them all, whereas structs always have their own unique data, and changing a copy does not affect the others.
I found this explanation confusing until I took the test and realized the difference.
In JS, creating an object or class instance and assigning it to two different variables matches the “copy” semantics above (the variable is a reference to the object).
The “struct” behavior (by value) is how primitives work in JS (string, bool, etc.). Objects never work this way.
Day 12 over! #100DaysOfSwiftUI
Structs (part two) with a checkpoint… day 11 was pretty straightforward! #100DaysOfSwiftUI
Structs, mutating
on methods, computed properties, property observers, custom initializers… it’s a lot but it was pretty easy to get through.
I think the only “new” concept (coming from JavaScript) was marking methods as mutating
.
Day 10 done so 10% of the way there! #100DaysOfSwiftUI
Dropping the parenthesis when calling functions with a closure blows my mind:
team.filter { $0.hasPrefix("T") }
The equivalent in JS:
team.filter($0 => $0.startsWith("T"))
Woo! The checkpoint test actually didn’t take me very long to complete.
Day 9 in the books! #100DaysOfSwiftUI
Really interesting that Swift has do
, but it’s not what you think!
do {
try throwingFunction1()
nonThrowingFunction1()
} catch {
print("Handle errors here")
}
In JS, that do
would be try
and no “try” is required before a throwing function.
Day 8 in the books! #100DaysOfSwiftUI
Awesome to me that this is valid:
func record(age: Int) { }
func record(year: Int) { }
Naming internal and external parameters separately is interesting too:
func square(of num: Int) -> Int {
return num * num
}
let result = square(of: 4)
Day 7 in the books! #100DaysOfSwiftUI
Day 6 is all about for
and while
loops.
I’ll be excited to learn the .map
and .filter
equivalents. I rarely use for
loops in JS and have only used while
a couple times in my career. 🫢
I wasn’t expecting to do FizzBuzz for the checkpoint test. There’s a first time for everything! #100DaysOfSwiftUI
No ===
in Swift (just ==
) is nice!
Enums being comparable is pretty cool too.
And switch
statements… is this the day I confess that I tend not to use them in JavaScript? Swift’s fallthrough
syntax seems much safer than JS needing a break
for each case
.
Day 5 done! #100DaysOfSwiftUI
This is really interesting:
let name: String
// …
name = "Chasen"
// Allowed once
In JavaScript, the “equivalent” (using const
) requires an initial value and doesn’t let you reassign it later. I like that Swift allows it be undefined and assigned just once.
Day 4 done! #100DaysOfSwiftUI
Coming from JS, there are some small differences in array and dictionary syntax. This really stood out to me (as nice and explicit):
let olympics = [
2016: "Rio de Janeiro",
2021: "Tokyo",
2024: "Paris"
]
print(olympics[2020, default: "Unknown"])
Day 3 in the books! #100DaysOfSwiftUI
This has a bug… can you spot it?
let temperature = 29
let converted = (temperature * 9 / 5) + 32
print("Celsius: \(temperature)")
print("Fahrenheit: \(converted)")
I thought the compiler might warn when losing precision like this, but I guess not!
Day 2 in the books! #100DaysOfSwiftUI
Is it cheating to do Day 1 on the same day as Day 0? 🙈 #100DaysOfSwiftUI
Cute that there’s a Day 0 to kick things off, with this as reading material: www.hackingwithswift.com/articles/…
I’m not trying to get a job as an iOS dev and I have a ton of dev experience; learning SwiftUI is a little hobby for me.
#100DaysOfSwiftUI
I’m stoked to start my Swift journey by following the 100 Days of Swift UI course: www.hackingwithswift.com/100/swift… #100DaysOfSwiftUI