And as always, you’ll find a summary of bits and pieces that caught our attention throughout November.
Let’s talk Inferno. Not the Dantean realm of eternal damnation but the open-source library of Metal shaders written for SwiftUI.
With the help of Paul Hudson’s video introduction and comprehensive documentation on how every shader works, you can add special effects to your projects on the GPU for maximum speed.
The latest Swift 5.9 release contains a handful of new features for debugging your code as interactive aids — to inspect your crashes in real-time, pause and inspect your crashed program or even trigger the debugger. Now even the backtracer is concurrency-aware and will correctly step back through asynchronous frames. And with the help of colorized output, you’ll be able to follow the results much better.
Some people have a negative attitude toward GeometryReader, believing it should be avoided as much as possible. However, if you understand how it works under the hood, it can become a very good friend.
As we know, GeometryReader occupies all the space provided by the parent view and aligns the origin of all child views with the origin of the container. However, in some complex layout scenarios, the layout may require multiple rounds of negotiation to decide on a stable result — especially when views need to rely on the geometry information to re-determine their position and size. In this article, we can see why .task(id:) might be the correct way to obtain information.
And one more note: There are other ways to set the alignments of the view, ways that can suit your needs even better — like aspectRatio (adjust the alignment of the image more conveniently), GridRow or the new visualEffect (if your app supports versions of iOS 17+).
Already supported since iOS 16, ViewThatFits is a simple and easy-to-use container for finding and using the most appropriate view among a given set of views — meaning that it selects the first child whose ideal size on the constrained axes fits within the proposed size. However, it does not impose ideal size constraints on subviews when it is finally presented. The logic behind it depends on the proposed space of its parent, the restricted axis, the ideal sizes of the subviews and the order of arrangement within the subviews.
Validating Asynchronous Code
While writing asynchronous tests doesn’t differ much from synchronous ones, here are a few important concepts to be aware of when validating asynchronous code:
- Mark your test definitions async and throwing.
- Remove the await keyword before types like UIViewController, as the class contains the @MainActor attribute and the test would run in a Main actor-isolated context.
- If your tests rely on test expectations for asynchronous validation, rewrite your code to use await fulfillment to avoid any deadlocks in your concurrent tests.
While checking if your code is working as expected, make sure that users are also not exposed. The statistics say that current authentication systems reveal glaring vulnerabilities, as it’s clear that the traditional combination of username and password is no longer sufficient. Which brings us to…
…And that brings us to Passkeys, a new authentication method that allows you to log into your account, whether on a website or an application. Take a look at how to integrate it into an iOS project. While the strengths make it a great candidate for the future standard for authentication, the sharing of passkeys between different ecosystems is definitely cumbersome.
Spending some extra time with naming your components might be a time-saver in the long run. It may sound like a simple concept, but the component we would make is now more reusable by nature without upfront investment. Let’s see how!
The main tip? Try disconnecting the use case from the name. For instance, for a user’s avatar and name, instead of UserProfileView we can use a more generic name, like ThumbnailView. Doesn’t take much effort but makes it reusable — without leaking its use case — and can be put into a shared UILibrary. As for Swift, we can create a typealias for the component with a more specific name, adding more context without introducing a new component.
Last but not least is the Chain of Responsibility, a behavioral design pattern that relies on handling events in a loosely coupled and scalable manner. It is a flexible and reusable pattern, but it can become complex if there are way too many handlers in the chain. It’s best used with a clear pattern within the chain, when the order on which the handlers are linked is well-thought-out and the system has been tested to ensure that requests are being processed correctly. And it’s best avoided if there’s a large number of handlers in the chain.