Swift5-7


Nov. 2, 2022

Cupcake Corner challenges

cute cupcake, cartoon - Stable Diffusion

Day 52 of #100Days was the challenges to the Cupcake Corner app - an app that allows you to build a one-row order, encode it as JSON and submit it to an API with a URLSession. To allow the order to be passed around, it’s an @ObservedObject which meant that a few extra hoops needed to be jumped through to make it Codable.

1) Whitespace validation

The tutorial app validates the order address by checking that each field is not empty, but it can be fooled by just entering some spaces. The first challenge was to fix that.

Oct. 31, 2022

Codable when the keys don't match

A common issue when working with JSON that you vacuum up from internet APIs will be that the key names in the JSON don’t match your property names. The JSON de facto standard of using snake_case in key names could be one cause, or perhaps you just take variable naming more seriously than the person who wrote the API.

We saw yesterday how using codable and the JSONEncoder in Swift makes moving between an object/struct in the code and a stringish representation of it simple. With a couple of small changes, we can also deal with the mismatched key/property name issue.

Oct. 30, 2022

Codable & JSON

encryption machine, comic 27970 - Stable Diffusion

If we mark a type with the protocol Codable, we’re specifying that this type has the capability of having it’s properties encoded to some format, and decoded back again.

So far in the #100Days this has been used to write and read data in UserDefaults, and to encode an object to send it as a URLRequest, then receive data back and create a new object from it. It’s a handy, powerful feature baked into Swift that just requires the developer to ensure any types that need this functionality comply with the Encodable and Decodable protocols that make up the Codable.

Oct. 28, 2022

Day 50 - @State vs @Observed again

Way back when, I was unclear about @StateObject and @ObservedObject (here , and here ). I still am.

But in today’s tutorial video, Paul clearly says that the @StateObject is for the single place in your app where the object is created, then everywhere else, use @ObservedObject. Trouble is, I just know from the Simple MVVM app I made if you wrap the single instance of the data model with the @ObservedObject, it still works.

Oct. 27, 2022

Day 47 - Habits App

pretty! woman holding a bag of trash, Artstation - Stable Diffusion

I’ve been mucking around with the Habits app too long - it’s started to look like procrastination. It already meets the specification , so I’m calling it an MVP and moving on.

This is the first app of mine I’ve loaded onto my phone and started using, and there are a couple of things I’d like to do with it. It currently just lets you specify how many days between an activity repeating - so if you say you should go to the gym every second day, and you complete that activity on Monday, “Gym” will make it’s way to the top of the list on Wednesday. While it’s waiting in the list for Wednesday to come around, it will show the “Due” time as being exactly 48 hours after you last pressed “done” on it. But if the habit you want is to go to the gym after work at 6:00pm that’s when you want it to be due. I’d like that.

Oct. 24, 2022

JSON encode/decode

Screenshop of Habits app

As usual, I’m spending way more time on the apps written from scratch in the 100Days series . The Habit tracking app I’m working on has been good practice, especially of the architecture of the simple list based app .

My version has a couple of refinements I quite like. I’m using a checkmark in a rectangle as the button to mark that activity as done, and I’ve added a nice fade to the checkmark as time goes on to represent the percentage of time from when it is done until it becomes due again.

Oct. 23, 2022

Refreshing SwiftUI Views

refreshing view, Rococo - Stable Diffusion

SwiftUI does some property wrapper magic to (very efficiently) refresh your views, but what if you want to force a refresh for some reason? Here’s the techniques I’m currently using to do that.

The tricks are below, but just so you can see them in context, here’s the sample app we’re working on. It’s a list of cars so you can keep track of how many of each kind you own. Here’s our data:

Oct. 22, 2022

You need to enjoy puzzles

frustrated worker, painting - Stable Diffusion

I’m writing the Habits list based app from #100Days and had a working MVP, then for some reason, decided to refactor by changing the subview I’d written as a function, into a struct. Some time later, I discovered that my list items were not updating correctly, so detective time.

I talked a little bit about the architecture yesterday - the item is a struct, and there’s a class containing an array of the items. Something like this:

Oct. 21, 2022

Purple warning - "Publishing changes"

It’s a pretty safe bet that if Xcode is saying there’s an error in my code, that it’s correct, and I am in error - not Xcode. Today I came across a situation where that might not be true.

I think the purple warnings are problems detected at runtime - I’ve heard of thread problems causing purple warnings. The error I was getting was “Publishing changes from within view updates is not allowed, this will cause undefined behavior.

Oct. 19, 2022

Drawing Feedback

Hedy Lamarr standing in front of a drawing, Kuvshinov Ilya - Stable Diffusion

Here’s the summary of my learning from comparing my efforts with Paul’s solutions to the Project Nine challenges from Day 46 of his 100 Days of SwiftUI course .

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.

Oct. 18, 2022

Project 9 - Drawing

Screenshot of Xcode and the preview showing some fancy graphics

These few days of #100DaysOfSwiftUI we made some pretty shapes by playing around with some of the SwiftUI systems for drawing on the screen, including paths, shapes, transformations, ImagePaint, drawingGroup() to use Metal rendering, blurs, blend modes and using animatableData for animating - which I think is the solution to an animation problem in my TimesTable app I hadn’t been able to solve yet.

Oct. 17, 2022

When it Works

Screenshot of swiftui code and the iphone simulator with a roughly drawn face

The little joy of something working. It’s one of the things that makes coding enjoyable. Like a good video game you have an overarching goal, but on the way you need to solve a large number of problems of variable complexity, and you get a little bit of dopamine for each one.

I think in every language I’ve ever learned, as soon as I know how to draw something on the screen, I start to get the urge to create a simple drawing application. When I was starting on Visual C++ and the MFC (Microsoft Foundation Classes) the book I used to get started built a drawing application as an example. It hooks into the benefit of being able to quickly see the evidence you’ve achieved something.

Oct. 15, 2022

Moonshot Feedback

Girl with a headset in a space command center, Kuvshinov Ilya, Mitsumayo - Stable Diffusion

I’ve watched Paul’s solution to the Moonshot challenges (the solutions are one of the perks of being a Hacking With Swift subscriber). When I’m solo learning like this its one of the few ways I can get any feedback on my coding, so I highly value it, and usually write one of these posts as a way to ensure I reflect on it.

Oct. 14, 2022

Moonshot Challenges

Another few coding challenges at the end of a tutorial app in the 100 Days of SwiftUI course. The app is a sort of information app - composed of navigation views going down into more detail about the Apollo space missions. The most exciting revelation for me was how straightforward it is to pull JSON into your apps data structures.

Challenge 1

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.

Oct. 13, 2022

Using Swift's map

“map, moon, transformation” - Stable Diffusion

In Day 39’ s Moonshot tutorial app, Paul uses .map on an array without much comment about what’s going on. I assume this might be a common concept in modern languages, but it was new to me.

First, here’s Paul’s code

    init(mission: Mission, astronauts: [String: Astronaut]) {
        self.mission = mission

        self.crew = mission.crew.map { member in
            if let astronaut = astronauts[member.name] {
                return CrewMember(role: member.role, astronaut: astronaut)
            } else {
                fatalError("Missing \(member.name)")
            }
        }
    }

Mission here contains an array of crew which is a struct with two strings, one of them being name, but self.crew (which belongs to the view we’re in) is an array of CrewMember which is a struct with a role: String and another struct astronaut. That sounds confusing, but essentially, an array of one type is being processed to return an array of another type where there’s a 1:1 relationship between the elements of each array.

Oct. 12, 2022

iExpense Feedback

I finally got around to looking at Paul’s solutions for the iExpense challenges .

Use the user’s preferred currency, rather than always using US dollars.

Same approach as me,

.currency(code: Locale.current.currency?.identifier ?? "USD")

except that he does the work in a local variable which is a bit neater. Since it appears in two places - the display view and the view for adding an expense, this would mean duplicating it, making it global (not rare for user default type settings) or passing it down through the view hierarchy. I feel either of the first two options are fine for this project, but Paul is thorough and extends the FormatStyle protocol, only for currency, to have a new computed property .localcurrency - which is a great solution.

Oct. 10, 2022

SwiftLint

I was watching a Tim Ruscica video about the things that highly effective developers do, and it called to mind a book I read years ago called Code Complete . It is the only book I ever owned that I immediately purchased the new edition when it came out. It was about the meta stuff around programming that is the difference between coding and developing. In particular, it got me invested in source control and testing.

Oct. 9, 2022

Testing, testing

I have unit testing in my list of goals , and if I’m going to throw this space trimming macOS utility up on the web, now might be a good time to figure out how to add unit tests to a project, how to write them, and how to run them. XCode is well set up for this, so it’s really no drama to do.

Although I haven’t worried with any unit testing up to this point in my iOS/Swift learning, in my previous programming work I did a lot of work with the large calculations involved in translating GPS coordinates and robotic positioning models where errors would be bad - so I’ve written a lot of tests over the years. I’ve also definitely felt the confidence you can dramatically refactor code with when you know the code has a robust test suite. I’m a big fan.

Oct. 7, 2022

Customizing the default About dialog for MacOS apps

The default Xcode MacOS targeted app has a built in “About” dialog called up from the “About ” menu item in the Mac menu bar. It wasn’t immediately clear to me how to customise this, but after digging through some MacOS apps on GitHub, here’s the answer.

When you app is being built, it looks for the file “Credits.rtf” in the app bundle. If that is found (or “Credits.html” or “Credits.rtfd” ) it’s used to build out the About dialog along with your app icon.

Oct. 6, 2022

CodeTrimmer - First MacOS App

I was listening to the StackTrace app this morning (episode 169 - “Choosing What Bugs to Ship” ) and one of the ideas discussed was taking the time to automate some of your development processes, partially to save time, but also because if you make a process simple and quick, you’ll be more likely to do it multiple times to improve quality.

Coincidentally, I’d been thinking about how often I paste some code from Xcode in order to display it in one of these blog posts. If it’s from the middle of a method, it will generally be indented a long way in, and there’s no point in displaying it like that (especially for a mobile reader) so I usually manually delete a heap of spaces from each line to left align it whilst keeping the needed indentation.