blog.iankulin.com

Code

Using LLMs for coding

I survey the rise of AI coding tools, from ChatGPT and GitHub Copilot to open source ecosystems, alongside skeptic concerns about training data, code quality, model collapse, and code exfiltration. I explain why these assistants suit my situation as an experienced developer new to modern languages, and trace my journey from paid Copilot to the free Codium and finally to running local models via Ollama and the Continue VSCode extension to keep client code private...

Copying Objects in JS

I take a look at copying objects in JavaScript for React state updates, covering why simple assignment fails, how the spread operator creates copies, and how to selectively replace properties during a copy. I also show why shallow copies fall short with nested data, demonstrating how to manually spread nested arrays for add and remove operations, and end by noting how the approach gets messy at deeper nesting levels...

Concurrency and channels in Go

I offer a beginner-oriented walkthrough of Go’s concurrency basics, built around a small demo program with a worker function that sleeps and reports. I introduce goroutines, then channels for passing values between the worker and the main program, explain why plain channel reads block, and show how a select statement with a default case enables non-blocking checks, finishing with closing the channel to release resources. The sample code is available on GitHub...

Clean code

After listening to a podcast episode about “humane” development, I describe my personal Swift coding style, which centers on being kind to whoever reads the code next. The principles I cover include following community conventions, writing code that reads like natural language, keeping functions small and single-purpose, avoiding hidden dependencies like globals, and using comments as temporary scaffolding that usually gets deleted once the code is written...

ImageRenderer()

A short SwiftUI example showing how ImageRenderer converts a view into a UIImage or CGImage. I build a simple behaviour ticket view, use a Save button to render it to an image, and display the saved result behind a toggle...

Ticket to ride

This is a progress update on my SwiftUI behaviour ticket app. Rather than the eventual goal of rendering tickets to PDFs or images for a share sheet, I cover exporting ticket data as a CSV text file, using a FileDocument struct adapted from Paul Hudson and SwiftUI’s fileExporter modifier, with code included...

FriendFace 61 Feedback

I compare my attempt at a Core Data caching challenge—storing fetched user data so the app can still display it after network failures—against Paul’s model solution. Differences covered include adding a merge policy for handling constraint conflicts, keeping ids as UUIDs, and placing MainActor.run inside the network fetch rather than after it...

61 Done

I complete Day 61 of #100DaysOfSwiftUI, decoding JSON and backing it up into a Core Data graph for display. I get stuck on one:many relationships and an id type mismatch, plus some unexplained Core Data console warnings that linger despite the app working...

Core Data basics - Part Two

Part two of my series on Core Data basics, in which I convert a SwiftUI master/detail garden-list app from structs to Core Data. I walk through defining entities in the Xcode data model, generating editable NSManagedObject subclasses, setting up a DataController with NSPersistentContainer, and fetching and saving data with @FetchRequest. I defer one-to-many relationships to the next part, and I draw much of the code from Paul Hudson’s 100 Days of SwiftUI...

Core Data basics - Part One

In the first part of my series on learning Core Data basics, I build a simple SwiftUI master/detail app that lists gardens and their plants using structs and arrays, as a starting point before converting it to Core Data in later parts. My code draws heavily on Paul Hudson’s 100 Days of SwiftUI course, with a GitHub link to the source...

FriendFace Feedback

A comparison of my SwiftUI solution to the FriendFace challenge (downloading and displaying user JSON) against Paul Hudson’s version from Hacking with Swift. Differences I discuss include handling user IDs, structuring preview data, loading and error handling in fetchUsers(), and UI choices such as colored circles for user status and a grouped list style for the detail view...

FriendFace

A write-up of my Day 60 milestone challenge in the 100 Days of SwiftUI course: I build a small app that fetches a JSON file of users, decodes it into Codable structs (including ISO-8601 dates), and displays them in a list with a detail view. I share my fetch and view code, note some friction with nested do/catch error handling, and add profile pictures via AsyncImage, deciding against implementing image caching in order to keep the challenge simple...

Project 12 Challenges

My solutions to the three wrap-up challenges from Project 12 of the Hacking with Swift SwiftUI series, which involve a FilteredList subview whose @FetchRequest is built dynamically in its initializer. The tasks add a predicate format parameter, replace the hard-coded predicate string with an enum using raw values, and support an array of SortDescriptor objects...

Bookworm Challenges

My solutions to the Project 11 challenges from the 100 Days of SwiftUI course, applied to Bookworm, a CoreData-based book tracking app. I add validation so books can’t be saved without a title or author, highlight one-star ratings in the book list, and add a date attribute to the Book entity that’s formatted in the detail view...

@Binding - data between views

I explain SwiftUI’s @Binding property wrapper, framed by an analogy to passing pointers in C. A short code example demonstrates a parent view passing an @State variable to a subview with the $ prefix, letting the subview read and mutate the value...

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

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