Skip to content

Hi! 👋 I'm Joseph Duffy. I enjoy building software. This website contains information about my commercial software, open-source projects, and blog posts. Welcome to my corner of the internet!

★ My Favourites


Overamped Icon

Overamped is a Safari Extension that redirects AMP and Yandex Turbo pages to their canonical versions, no matter how the page was opened.

Four Squares

Four Squares Icon

Four Squares is a game of memory, skill, and concentration available for iOS, iPadOS, and macOS. Watch what happens each turn and replay what you see.

Hosting DocC Archives

At WWDC21 Apple introduced DocC, a tool for creating archives of Swift documentation that includes the static files required to host a version of the documentation on a website.

In this post I will summarise various methods of serving a DocC archive:

  • Netlify
  • Vapor middleware
  • nginx
  • Apache

All the examples provided here are hosting the DocC archive for VaporDocC, the Vapor middleware I wrote for hosting DocC archives.

Keep Reading

HashableByKeyPath framework release 1.0.0

Today I have released the 1.0.0 version of a Swift package that aids with adding Equatable and Hashable conformance by using KeyPaths.

The package is available on GitHub.

I created the Swift Playground that sparked this concept in December 2018, so this concept has been rattling around in my brain for a couple of years. The API has changed a lot since the original concept, but the core has stayed the same: a protocol that requires a single function to be implemented that uses KeyPaths to synthesise Equatable and/or Hashable conformance.

Keep Reading

Recent Entries

HashableMacro 1.0.0

Release Notes

Initial release with support for adding Hashable conformance on iOS, macOS, watchOS, tvOS, visionOS, and Linux.

Pull request Perform item reloads in a separate batch of updates on opennetltd/Composed

This works around a bug from ~iOS 14 that causes the last N items in a section to ignore any updates applied to them when N items are deleted from the same section and the items are at the end of the section.

This also removes the conversion of inserts/removals in to updates, which reduces the need to account for these synthesised updates and also more closely matches the intent of the user; if something has truly moved or been updated the appropriate methods can be used, while removals and inserts that happen to result in the same position will not animate as a refresh.

This also fixes the crash that #6 was originally aiming to fix. It became much easier to reason about the changes once the reloads were not synthesised and were using the post-updates index paths. I think this probably fixes some other bugs. At a minimum the existing tests were updated or still passed, plus new tests have been added.

I also created, which adds some more tests to the integration project. These are mostly used to validate that the unit tests here are correct according to UICollectionView, e.g. it does not crash, request any unexpected cells, or fallback to a reloadData.

Pull request Fix reload delete same index path on opennetltd/Composed

This is an improvement but it's not quite a fix yet.

I think the issue is in the transforming of the index paths. We probably need to work with a mixture of the current and the transformed index paths in ChangesReducer.removeElements(at:) but I can't figure out the right mix and need to step away for a bit to clear my head of this, hopefully coming back with "fresh eyes."