April 24, 2020

I had a peak of interest for SwiftUI a while back. But after that experience I feel like I only want to build “handcrafted artisanal” UIKit apps instead. Getting to 90% is WAY faster with SwiftUI. But getting to insanely great takes another 90% and what feels like a lot of hacky code.

February 2, 2020


February 2, 2020

Tangerine Habit Tracker

Tangerine is the first habit tracker that I’ve been able to really stick with. It’s a pretty new app but came out of the gates strong. If you’re looking for an app to help you keep on track with all your 2020 resolutions1 I can’t recommend Tangerine enough. I have a few quibbles of course. Like completing a task after midnight breaks your streak. I understand the reasons for this. The developer is aware and is looking to solving this in the future.

January 30, 2020

Using Self Executing Closures to Run Code in SwiftUI

Not being able to run arbitrary code in SwiftUI view builders can be quite annoying. The other day I realized it’s possible to use self executing closures to work around this! Here’s a contrived example that creates a stretchy header: struct ScrollThing: View { var body: some View { ScrollView { VStack(spacing: 0) { GeometryReader { g in Color.white .offset(y: { let offsetY = g.frame(in: .global).minY return offsetY > 0 ?

December 25, 2019

UICollectionView Ergonomics

One of my favorite things in UIKit is UICollectionView. I love how versatile it is. With iOS 13 it got even better with the diffable data source and compositional layout APIs. However, when dealing with collection views there’s a lot of boiler plate one has to take care of. In this post I want to share some of the code I’ve written to make working with collection views a bit nicer.

October 3, 2019

Combine's Sequence Publisher Missing First Element

Just had a fun run in with a bug in Combine. Any Sequence can produce a Publisher that publishes each element in the sequence when you subscribe to it. You might have a custom sequence implementation that counts from 1 to 9: final class Incrementer { var value = 0 func next() -> Int? { value += 1 guard value < 10 else { return nil } return value } } extension Incrementer: Sequence { func makeIterator() -> AnyIterator<Int> { return AnyIterator { self.

October 2, 2019

Plantry 3.4: Search

After a brief holiday in 3.3, Search is now back in Plantry and it’s better than ever. Built using SQLite’s FTS4 it enables our users to filter recipes based on ingredients, their name and so on. This is something we’ve been wanting to do a long time, feels great to finally ship. Many thanks to Gwendal Roué for his amazing work on GRDB.swift and the quick responses to issues. I also finally had a use for the quintessential reactive programming example: debouncing search queries!

October 1, 2019

Using Combine to Supplement Delegates With Publishers

Anyone who’s ever written an iOS app has come in contact with the delegate pattern. It’s a great pattern and fills an important role in iOS development. However, sometimes when you’re writing your own custom classes it can feel like a bunch of boilerplate just to notify a delegate that something happened. You might resort to adding a couple of callback properties instead, but those come with their own baggage.

September 18, 2019

Plantry Goes Dark Mode

When we first started work on Plantry it had another name and a different look. The rumors of an OLED iPhone were rampant at the time, it was too tempting to not make an app with a true black look. After a while we came to the conclusion that maybe it was more appropriate for a cooking app, commonly used in a bright kitchen, to have a lighter and more friendly look.

February 25, 2019

Plantry 2.8

Realized I’ve been terrible at promoting my own work. Last post mentioning my app was in October. Anyways, Lita has been renamed to drumroll Plantry! A bit more international, a bit more playful and on the nose. It’s about plants. And plans. And trying new foods! Version 2.8 is waiting for review as we speak. Since version 2.3 — which is the last version I blogged about — we’ve introduced a way of manually picking any recipe you want for a plan, instead of just shuffling.