blog.iankulin.com

blog.iankulin.com

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...

Why?

In this short post, I ask why the Xcode preview window has to be resized every time it opens, with the answer provided as an embedded YouTube video...

Updating stored JSON due to a struct change

A short walkthrough of migrating persisted app data in a Swift app after changing a Codable struct: I copy the old struct under a versioned name, and init() attempts to decode saved JSON with the new model first, falling back to the old one and converting items across. I note the migration code is deliberately messy and temporary, since the app only exists on my phone and a couple of simulators...

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...

List Apps

Reflecting on the Day 47 habit-tracking milestone challenge, I observe that simple SwiftUI list apps follow a common recipe: Identifiable/Codable structs, an ObservableObject collection with @Published state, and a List inside a NavigationView. I outline that pattern, its benefits for building quality apps quickly while staying HIG-compliant, and the risk that such apps end up looking and feeling like every other list-based offering...

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...

Musings on Data

Losing some enthusiasm for my online SwiftUI course, I weigh starting on app ideas from my notebook instead. The main gap in my knowledge is data persistence, so I consider the options: Core Data with CloudKit, Firebase, or simply writing files to the app sandbox, noting that a background in large relational databases means adjusting my thinking for small-scale apps. Whether to push on with the course or start building is left undecided...

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...

Using AI to Generate Icons

After hiring a designer on Fiverr for CodeTrimmer icons, I try generating them locally with DiffusionBee, a free Apple silicon build of Stable Diffusion, on an M1 MacBook. I show outputs for a scissors-over-code prompt, note the permissive CreativeML Open RAIL-M license, and observe that prompt-writing is a skill, with results good enough for toy apps or as starting points for design ideas...

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...