swift posts

Subscribe to just swift posts via RSS.

Parsing HTML Fast

The urge to overengineer something recently befell me, and the target of that urge was the way Tusker handles HTML parsing. Mastodon provides the content of posts (and profile descriptions, and some other things) as HTML, which means that, in order to display them properly, you need to parse the HTML, a notoriously straightforward and easy task. For a long time, the approach I took was to use SwiftSoup to parse the HTML and then walk the resulting node tree to build up a big NSAttributedString that could be displayed.

And while that technique worked perfectly well, there were a number of downsides that I wasn’t entirely satisfied with. First: SwiftSoup alone is a big dependency, at around ten thousand lines of code. Since it’s shipping in my app, I take the view that I’m responsible for making sure it doesn’t break—and that’s a lot of surface area to cover (moreover, since it was ported from a Java library, the code is extremely un-Swift-y). Second: it’s not especially fast. Partly because of its aforementioned nature as a Java port (everything is a class, lots of unnecessary copies), but primarily because it’s just doing more than I need it to (the first rule of optimization is do less work): it was parsing a string into a tree and then I was flattening that tree back into a string.

The last time I needed to do something similar, I used lol-html, Cloudflare’s streaming HTML rewriter. But, while that worked (and is still in use for my RSS reader app), it’s written in Rust, and I didn’t want to introduce significant additional complexity to the build process for Tusker. So, writing a new HTML parser in Swift seemed like a great idea.

Theming iOS Apps is No Longer Hard

Well, at least not for the same reasons. I figured I’d write a brief follow-up post, but unless you’ve been living under a rock, you’ll have heard that UIKit gained support for custom traits in UITraitCollection with iOS 17. They work very similarly to SwiftUI’s environment and are exactly what I wanted.

A Hero View Controller Transition in SwiftUI

Out of the box, SwiftUI has a matchedGeometryEffect modifier that makes it relatively easy to build hero transitions (a style of transition where a new screen is presented and part of the source screen changes position and size to reach it’s place on the new screen). It’s cool that SwiftUI includes this out of the box, but unfortunately it has a few limitations that make it unsuitable for certain use cases. Particularly for me, that it doesn’t work with presenting another view. Most examples on the internet[1] work around this by faking a custom presented view: just slap a full-screen background color down and show your content on top of it. That’s essentially the same as a presenting a full-screen view, with the one major caveat that the pseudo-presented view can only cover the containing hosting controller. And if that controller isn’t full-screen (say, if it’s presented as a sheet), you can’t present anything that’s truly full-screen. So, let’s build a custom hero transition that actually presents it’s content across the entire screen.

Theming iOS Apps is Still Hard

Sorry to be the bearer of bad news. Last year, Christian Selig wrote a blog post about the annoyances of theming iOS apps. I won’t retread his entire article, but the gist of it is that there is no nice way to easily apply a theme to an entire iOS app. Either every view/controller has to listen for theme change notifications and update itself, or you have to resort to hacky workarounds to force all colors to update[1].

Calling Swift from Rust

From the person that brought you calling Rust from Swift comes the thrilling[1], action[2]-packed sequel: calling Swift from Rust! For a recent project, I found myself needing to call into Swift from a Rust project (on both macOS and Linux) and so am documenting here in case you, too, are in this unenviable situation.