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

Nevis

Nevis Icon

Find and install applications found in DMGs and ZIPs.

Configurable to watch directories, ask before performing actions, moving used files to trash, and is completely free to try.

Download NevisVisit Nevis Website

Gathered

Gathered Icon

Gathered is an app that facilitates the viewing, recording, and sharing of over 25 sources of data available on iOS and iPadOS devices, from the GPS and accelerometer to the advertising identifier and the WiFi. Gathered is the perfect app to enable the recording of all the data required to calulcate position, acceleration, and ambient conditions of the device.

Download Gathered on the App Store

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

iOS Share Sheets the Proper Way - Locations


Sharing a location on iOS is something that not a lot of apps need, but after requiring it for my latest app, Scanula, I found that there isn't a good resource explaining how to do it properly. This is the first post in a series of planned posts going over a few of the tips, tricks, and common pitfalls I have found while working with iOS Share Sheets.

Keep Reading

Recent Entries

Supporting Multiple Swift Package Versions Without Breaking Compatibility


The Xcode 12 beta includes Swift 5.3 but drops support for iOS 8.x. This means that Swift packages that support iOS 8 will cause a warning:

The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.

It's not possible to remove this warning within a project that depends on a Swift package with a deployment target of iOS 8, but it is possible to fix this in the dependency without removing support for iOS 8 for older versions of Swift. There are multiple way this can be accomplished.

Keep Reading

Pull request Rewrite delegates to take perform update closures on composed-swift/Composed


This is a major API change so is in a v2 branch. If we agree on a direction we could start adding PRs in to this branch.

This change would enable multiple changes to be applied at once, e.g. by requiring balanced calls to mappingWillBeginUpdating and mappingDidEndUpdating and only performing the updates when an equal number of mappingDidEndUpdating calls have been made. This could be a small performance improvement but would also improve animations.

By adding the performUpdate closure the changes to the model layer can be applied only when the consumer is expecting them, e.g. for UICollectionView this would be inside performBatchUpdates and would fix the existing crashes that occur when performing a change when there are pending layout changes.

Some tests and types have been commented out since this is more of a starting point for a discussion around the API than it is a solid implementation.

This is the closest I can see the API being (although it's still a breaking change) but maybe a bigger change would be better.

The biggest PITA is that the sections need to keep track of "current" data (e.g. what's being displayed by a collection view) and the "pending" data (e.g. what's about to be applied). I don't think this adds any memory overhead but it does add much more to the knowledge required when implementing a section.

Pull request Sort symlinks in order required for unzip on weichsel/ZIPFoundation


Changes proposed in this PR

  • Fix extraction order of symlinks

Tests performed

  • Existing tests
  • Extracting the AltServer download from https://altstore.io/

Further info for the reviewer

This needs more tests to ensure full coverage, but also to prove that this was previously broken and is now fixed.

The added function is public because I'm using it to extract a subset of the entries in the archive that contains symlinks.

Open Issues

#185, possibly #62.

Pull request ComposedSectionProvider fixes on composed-swift/Composed


These were quite hard to track down since the errors that would occur would often be visual and not a crash, although in some scenarios it did seem to trigger a crash.

I think this highlights the need for a much larger test suite.

Sidebar

It also made me question the insert(_:at:) functions because it's not really clear what the index is. Should it insert it at the index in the context of the sections and providers (as it does now), or just sections?

For example, with:

  • Section A
  • Section Provider
    • Section B
    • Section C
  • Section D
  • Section E

If I insert a section at index 3 should it look like:

  • Section A
  • Section Provider
    • Section B
    • Section C
  • New Section
  • Section D
  • Section E

or

  • Section A
  • Section Provider
    • Section B
    • Section C
  • Section D
  • New Section
  • Section E

Pull request Fix crash when performing update while animating on composed-swift/ComposedUI


The completion block is called when the animation has completed, but at the end of the updates block the data has already been updated (from the perspective of the UICollectionView).

Not calling reset() and setting defersUpdate = false could cause crashes e.g. due to changes being applied multiple times.

The best way to recreate this is to have a series of updates occur very close to each other but with the "Slow Animation" setting enabled in the simulator.

This change might also apply to table views, I have not checked.

The crash would often be along the lines of "Tried to delete section at index 11 but there were only 11 sections" or would occur in elementsProvider(for:) with the error "No UI configuration available for section 11" when performing a non-data change e.g. a reload of a section