Archive for May 30, 2023

Tuesday, May 30, 2023

Rewriting Remotion in SwiftUI

Dan Wood:

It took a while — August 2022 — before we felt that we were targeting a new enough version of macOS that we could feasibly start using SwiftUI in our code base. Since then we haven’t looked back: Development is faster, the app is more stable, and new teammates are ramping up faster thanks to the simpler code base.

We now think: If you are a macOS or iOS developer who hasn’t yet taken the plunge yet, now is a great time to start writing a new app using almost exclusively SwiftUI, and use its friends Combine and concurrency for the data flow.


While SwiftUI is all you’ll need for a basic Mac or iOS application, there are still quite a few gaps that will require you to partially make use of classic Cocoa views. In our code base, for example, we need some access to NSEvents, text input, and tweaking the first responder that just aren’t possible with pure SwiftUI. Fortunately Apple has provided bridges — the NSHostingView and NSHostingController for embedding SwiftUI in a Cocoa view, and NSViewRepresentable and NSViewControllerRepresentable for embedding a Cocoa view in a SwiftUI view. A really powerful technique we can’t neglect to mention is combining these two together, as described in this SwiftUI Lab article.


Rewriting SoundCloud in SwiftUI

Matias Villaverde and Rens Breur:

We will share all the mistakes we made in the past two years while rewriting the whole SoundCloud iOS application in SwiftUI. The talk emphasizes problems that can happen when writing SwiftUI applications at scale. Hopefully, many engineers find our mistakes and learnings useful for adopting and migrating UIKit to SwiftUI.


SwiftUI Notes Before WWDC 2023

Here are some posts I’ve been collecting since iOS 16 and macOS 13. Hopefully they will soon be outdated.

Phillip Caudell:

Has anyone got NavigationSplitView working reliably on macOS yet? Even the NavigationCookbook demo from Apple has broken things like double clicking to open new window?

Peter Steinberger:

“It is really cool, wild even, but also, if you use this, it crashes. Really unfortunate. Made it into iOS 16 GM as well.” -@mbrandonw on NavigationPath in SwiftUI

[Update (2023-06-02): Brandon Williams: “[This] bug was fixed in Xcode 14.1 beta 3. There are still plenty of bugs in SwiftUI navigation APIs though.”]

Phillip Caudell:

The new SwiftUI navigation API straight up doesn’t work if you have a List that supports selection.

Worse, the same code works on macOS but silently fails on iOS.

This is what drives me nuts about SwiftUI: how can something so simple be so broken?

Gwendal Roué:

Both List and LazyVStack are not as lazy as expected: they both access all elements in the collection, even if they are not rendered (it’s still iterating the million items as I’m writing, poor boy).

Damien Petrilli:

So it seems Apple changed the way the TabView with paging is rendered causing the bug when you resize the content of a page within it.

The lesson I am learning doing SwiftUI is to never trust Apple provided views and always make your own… unlike it used to be in Cocoa

Phillip Caudell:

Another day, another serious SwiftUI bug: List on macOS won’t select its initial value if the binding has an optional value type. Works on iOS, fails on macOS.

Worse, changing to non-optional then works, but then doesn’t compile on iOS (FB10013937)

Phillip Caudell:

Add a .onDrag() handler to an item in a List. Now try select the item. You can’t.

Adding a drag handler literally breaks the entire List. People have been complaining since last year[…]

Christophe Sauveur (via Hacker News, tweet):

I somewhat regret not being able to use SwiftUI in this project. I have the feeling that it is a great technology, but I reckon now that it is probably not suited for my specific use case. However, I still don’t know if I was doing things the wrong way or not. I still plan to use SwiftUI for the updated version of Nihongo no Kana, but as an iOS/iPadOS app with much less frequent redraws, I suppose it won’t be an issue.

Maybe SwiftUI over AppKit is not ready yet. The authoring tools for The Untitled Project are not build as a Catalyst app and do not rely on UIKit. One of the benefits of this refactor however is that there is absolutely no delay whatsoever and everything works perfectly. Sure, it is way more verbose and Auto Layout is not the most pleasing tool to use. But you also get much more control over the behaviour of the app and everything can be meticulously tweaked to your desire.

Daniel Jilg (via Peter Steinberger):

The app is also hard to develop because we seem to be fighting against a host of bugs and unclear behaviours in SwiftUI on macOS, even in the newest versions.


The iOS app will lose its editor and become a viewer app.[…] Going forward, Dashboard [for the Web] will be our primary and canonical app. It will receive updates first, and any support requests regarding the Dashboard will float to the top. Once a feature is more stable, we’ll try and port it to the macOS and iOS apps.

Andreas Monitzer:

The weird thing is that SwiftUI has all the disadvantages of being non-native while not being cross platform (except iOS/macOS, but there’s Catalyst for that). Also, the documentation is bad.

Christian Selig:

I’m legit looooving how easy SwiftUI is making it to add some new cool views to Apollo, but it takes the wind out of your sail a little when alongside the smooth UIKit ones the SwiftUI animations look so choppy[…]

Bruno Rocha:

I can’t stress hard enough how awesome SwiftUI’s previews are. […] To be fair, the previews aren’t perfect. I had a frequent bug where the preview refused to show up and was unable to do any form of debugging on the preview itself, and a lot of people reached out to say that the previews are painfully slow on their older Macbook models, but it generally works well and I’m very happy we finally have official hot-reloading support in iOS.


While Burnout Buddy took me a couple of weeks to build, the majority of that time was spent on the logic and architecture. The UI itself for the entire app was built in just a couple of minutes.

It’s important to mention that this is not always true. As we’ll see down below there’s an entire category of “more complicated” products where SwiftUI is actually extremely detrimental to development speed, but we should still appreciate that SwiftUI works amazingly well for the more straight-forward category of projects that the majority of developers deal with. It’s also not too surprising that this is the case considering that they have been Apple’s primary target audience for Xcode features since the dawn of iOS.


SwiftUI forces you to shape your model in a way so that the complete structure and state of all views are static and known well in advance, which while not an impossible task, can be insanely difficult for views that have lots of moving parts and conditions.

Steve Troughton-Smith:

Another day, another fatal SwiftUI problem I have to now drop everything to work around.

Related to the last one, but Picker popups now auto-size to the longest menu item, ignoring all other layout cues.


I did everything right; this is a 5-line SwiftUI view wrapped in manual UIKit layout, treated with oven mitts to minimize potential damage. And it still went wrong.


Do note, as you flip through these three screenshots, that the same SwiftUI code has different layout on each. You simply can’t set it and forget it. You gotta re-test every OS you support with every SDK update and OS point release.

This kind of software decay is completely opaque to the developer; because Apple provides no kind of macOS Simulator to run older OSes, and TestFlight does not support macOS 11, devs relying on SwiftUI will be shipping bugs like this without knowing, without having a way to test.

Damien Petrilli:

Code works perfectly when compiled directly on the device but crashes when deployed through TestFlight and only for some devices…

And no way to debug as it’s internal. So you have to isolation the views and try alternatives to not trigger the bug.

Brian Webster:

So, the thing I couldn’t get SwiftUI to do is this layout, with the following conditions:

  1. Both vertical stacks should size to the width of the stack’s widest control (e.g. the “Import whatever version is available” button).
  2. The vertical stacks should be just as tall as needed to fit the controls and wrapped texts.
  3. The window should autosize to fit the stacks on both axes.
  4. The General tab is much smaller, but the window should *not* change size when switching tabs.


That’s the thing though, it’s absolutely trivial in AppKit (and I’d guess UIKit too). Just shove everything in an NSStackView and you’re done. I was genuinely surprised I couldn’t get it to work in SwiftUI without crazy shenanigans.

Helge Heß:

I’m slowly becoming a SwiftUI Table view expert. It can be a weird thing, especially cross platforms (iPadOS vs macOS have a set of different behaviours). E.g. on macOS “sections” do not become proper (sticky) group rows, which is quite weird given that this is an intrinsic NSTableView feature, they just scroll like regular contents.

On iOS there is “some” stickyness, but in a somewhat crazy way: a section title propagates to the content of the first column. Which breaks if it is short (overlaps w/ the second column). Also sections contents on macOS clip and don’t on iOS. And section contents on macOS respond to clicks, but not on iOS.


Anybody dealt with this macOS table-selection weirdness before?

It’s only happening for a small number of testers, and I can’t repro, so it’s a pretty frustrating bug!

Steve Troughton-Smith:

Every WWDC from here on in I’ll be looking at from the perspective of ‘can you make better apps with SwiftUI vs not-SwiftUI?’. The answer right now is ‘no’, not for the apps I want to build and the platforms I want to build them for, but boy would it sure be nice to say yes and start using more of AppKit in my cross-platform apps.


Building Large-Scale Apps With SwiftUI

Mohammad Azam (via Christian Tietze):

I have been experimenting with MV pattern to build client/server apps and wrote about it in my original article SwiftUI Architecture - A Complete Guide to MV Pattern Approach. In this article, I will discuss how MV pattern can be applied to build large scale client/server applications. […] The main idea behind the MV Pattern is to allow views directly talk to the model.


Based on Apple’s recommendation in their WWDC videos and code samples and my own personal experience, I have been implementing a single aggregate model, which holds the entire state of the application. […] Once, you have identified different bounded contexts associated with your application you can represent them in the form of aggregate models.


To prove that a View Model unit test does not verify user interface elements, simply remove the Button view or even the Text view from the ContentView. The unit test will still pass. This can give you false confidence that your interface is working.

Pet peeve: the parameters to XCTAssertEqual() should always have the actual value first and the expected value second.

I do not recommend testing Core Data with NSInMemoryStoreType because a lot of features don’t work with it, the performance characteristics are skewed, and having an actual file helps track down memory management bugs. I find that, with modern SSDs, using NSSQLiteStoreType with a temporary folder is fine, and there are various pragmas to make it go faster. If you really need in-memory, use /dev/null/DatabaseName as the file path.