blog.iankulin.com

Swift5-7

Cupcake Corner challenges

My solutions to the day 52 challenges for the Hacking with Swift Cupcake Corner app: trimming whitespace before validating the order address, showing an alert when the order submission to the API fails instead of just printing, and converting the Order class to a struct inside an ObservableObject wrapper to eliminate the manual Codable code. I present each change with Swift code snippets and links to the corresponding GitHub commits...

Codable when the keys don't match

How to decode JSON in Swift when the key names don’t match your struct’s property names. I cover using a CodingKeys enum to map JSON keys to properties manually, and the simpler keyDecodingStrategy option for handling the common snake_case versus camelCase mismatch...

Codable & JSON

In this beginner-level look at Swift’s Codable protocol, I explain that it combines Encodable and Decodable and is applied automatically when a type’s properties are all Codable. I use simple code examples to demonstrate encoding a struct to JSON with JSONEncoder and decoding JSON back into a struct with JSONDecoder. I flag more involved cases, such as decoding JSON with snake_case keys, as topics for later posts...

Day 50 - @State vs @Observed again

I revisit my ongoing confusion between SwiftUI’s @StateObject and @ObservedObject property wrappers. A tutorial video states the standard rule — @StateObject where the object is created, @ObservedObject everywhere else — but I note that my MVVM app still worked with @ObservedObject on the single data model instance. Attempting to resolve this, I use Xcode’s jump-to-definition to compare the wrappers and find an extra Wrapper struct in @ObservedObject’s implementation, which I set aside to revisit later...

Day 47 - Habits App

I wrap up my Habits app as an MVP, the first of my own apps I have actually installed on my phone, after 120 days on the 100 Days of SwiftUI course with only day 47 completed. Possible future features include setting habits due at a specific time, like 6pm, rather than a fixed interval after the last completion. A growing backlog, including a custom picker for a times table app, remains deferred...

JSON encode/decode

Progress on my SwiftUI habit tracking app built for the 100 Days challenge, covering UI refinements like a fading checkmark and the shift from simulator testing to daily use on a real iPhone. Persistence uses Swift’s built-in JSON encoding with UserDefaults, which works well until the struct changes — I discuss the resulting decode failures and the lack of a simple way to decode missing properties using default values...

Refreshing SwiftUI Views

Ways to force a SwiftUI view to redraw, demonstrated with a sample app that tracks a list of cars and their counts. The core technique is toggling a @State property that gets passed into subviews, which I then trigger via pull-to-refresh with .refreshable(), on app activation by watching scenePhase with .onChange, and on an interval with a published Timer and .onReceive...

You need to enjoy puzzles

After converting a SwiftUI subview from a function to a struct, list items in my habit list app stopped updating correctly. Suspecting a value versus reference type issue, I distilled the problem into a minimal ObservableObject example, only to find that both the example and the original app now worked. The post walks through the code and the debugging process but ends without an explanation of what caused or fixed the bug...

Purple warning - "Publishing changes"

I hit SwiftUI’s publishing changes from within view updates purple warning in Xcode 14 when a button in a list updates a model, and after research I conclude it’s likely an Xcode bug rather than a code mistake. Adding a button style modifier silences the warning as a temporary workaround, with newer Xcode versions possibly fixing the issue...

Drawing Feedback

I compare my solutions to the Project 9 drawing challenges from Paul Hudson’s 100 Days of SwiftUI course, covering an Arrow shape, making its shaft width animatable using AnimatableData, and a ColorCyclingRectangle with a controllable gradient. My closing aside considers whether to use US or UK spellings like “color” in Swift code...

Project 9 - Drawing

This is my #100DaysOfSwiftUI journal entry covering days on custom drawing: paths, shapes, transforms, ImagePaint, drawingGroup with Metal, blurs, blend modes, and animatableData. I walk through the challenge solutions, building an Arrow shape with animatable line thickness and a ColorCyclingRectangle whose gradient endpoint is controlled by sliders, and I note the lesson I learned from not using git for scratch code...

When it Works

A short reflection on what makes coding enjoyable: the steady stream of small problems to solve on the way to a bigger goal. I note the urge to build a simple drawing app hits in every new language I learn, from Visual C++ and MFC to SwiftUI...

Moonshot Feedback

A comparison of my SwiftUI solution to the Hacking With Swift Moonshot challenge against Paul Hudson’s, covering choices like whether to extract sub-views into separate files and using a List versus a ScrollView with HStacks. The key difference I discuss is a toolbar toggle built with a Button instead of an Image with a tap gesture, since using standard controls as intended gives screen readers the information they need for accessibility...

Moonshot Challenges

My solutions to the three wrap-up challenges for the Moonshot app from the 100 Days of SwiftUI course, an information app about the Apollo missions. My work covers displaying formatted launch dates, extracting the crew view and a custom divider into separate structs, and adding a toolbar toggle between grid and list mission layouts, with some notes on the tradeoffs of splitting views out...

Using Swift's map

While working through Day 39 of the Hacking with Swift 100 Days of SwiftUI course, I explain Swift’s map method, which applies a closure to each element of a collection and returns a transformed array. Simple Playground examples demonstrate mapping integers to strings, with equivalent forEach and for loop versions included for comparison...

iExpense Feedback

I compare my iExpense SwiftUI challenge solutions against Paul Hudson’s, covering preferred-currency formatting, styling expense amounts by value, and splitting the list into personal and business sections. After investigating why my ForEach-based split deletes the correct item despite warnings about offset mismatches, I find that SwiftUI’s onDelete already passes correct array indexes and conclude that my approach beats Paul’s filtered-array solution...

SwiftLint

Prompted by a video on effective developer habits, I finally add a linter to my Swift workflow. I cover installing SwiftLint and hooking it into Xcode builds, adjusting rules via a swiftlint.yml config file, and selectively disabling rules with code comments. My approach is to enable all optional rules up front, then decide for each violation whether to change the code or drop the rule...

Testing, testing

A walkthrough of adding unit tests to an existing Swift project in Xcode, using my CodeTrimmer macOS utility as the example. I cover adding a unit testing target, writing XCTest functions for the stripSpaces() method, and running the tests to see the results...

Customizing the default About dialog for MacOS apps

A short how-to on how I customize the default About dialog in a macOS app built with Xcode: add a Credits.rtf (or .html or .rtfd) file to the project, and its contents appear in the dialog after a rebuild...

CodeTrimmer - First MacOS App

Inspired by a StackTrace podcast episode about automating small development tasks, I built my first macOS app with SwiftUI: a utility that strips excess leading indentation from code copied out of Xcode, a chore I previously did by hand before pasting code samples into my blog posts. Screenshots show the paste-and-strip workflow, and I found the move from SwiftUI iOS development to macOS nearly effortless. My source code is linked...