Articles, podcasts and news about Swift development, by John Sundell.

A Swift developer’s WWDC dreams - 2020 edition

Published on 21 Jun 2020

With just a few hours to go until WWDC20 kicks off with the first ever online-only Apple keynote, I thought I’d do the same thing as I did last year, and share a few of my biggest Swift-related dreams for this upcoming WWDC.

These are not really predictions, nor are they based on any form of insider information — instead they’re simply my biggest wishes for Apple’s upcoming conference when it comes to Swift and its related tooling. Let’s jump right in!

SwiftUI 2.0

Whether or not you consider SwiftUI in its current state to be “production ready”, I think it’s fair to say that a lot of developers are anticipating significant upgrades to Apple’s new UI framework during this year’s conference.

While I know from speaking to Josh Shaffer on the podcast that Apple deliberately kept the initial API of SwiftUI narrow, in order to focus on its core set of building blocks during its first year as a public framework, I’d expect its scope to grow significantly with this year’s release.

Besides the classic “bug fixes and performance improvements”, I’d personally like to see changes such as a SwiftUI-native equivalent to UIKit’s UICollectionView, built-in support for other common views (such as activity indicators and map views), and a more powerful, NSAttributedString-style text API.

Although we’ve already been able to add support for the above types of views ourselves — for example by bringing existing UIKit-based views into SwiftUI using UIViewRepresentable, or by building brand new ones using SwiftUI itself — having a wider set of commonly used views built into the framework would be incredibly convenient.

Let’s take a closer look at UICollectionView as an example. While it’s totally possible to quickly create a very basic version of of a grid-based SwiftUI view, recreating the entire collection view API would require a lot more work. Here’s what such a basic grid implementation could look like, using SwiftUI’s ViewBuilder function builder, along with nested instances of HStack and VStack:

struct Grid<Cell: View>: View {
    typealias Position = (x: Int, y: Int)

    private let content: (Position) -> Cell
    private let size: (width: Int, height: Int)

    init(width: Int,
         height: Int,
         @ViewBuilder content: @escaping (Position) -> Cell) {
        self.content = content
        self.size = (width, height)
    }

    var body: some View {
        HStack {
            ForEach(0..<size.width) { x in
                VStack {
                    ForEach(0..<self.size.height) { y in
                        self.content((x, y))
                    }
                }
            }
        }
    }
}

The above implementation uses tuples as lightweight types. Check out this article to learn more.

The fact that the above is all that it takes to create a basic grid view is really a testament to just how powerful SwiftUI’s API already is, but the above implementation is still a far cry from all of the flexibility that UICollectionView (and its AppKit equivalent) offers, especially when it comes to things like flow layouts and dynamic item sizes.

Swift Package Manager for apps and playgrounds

Ever since Xcode started offering built-in support for the Swift Package Manager as part of last year’s release of Xcode 11, I think it’s fair to say that Swift’s official dependency manager has been significantly growing in both power and popularity.

While it’s always been possible to build a Swift package using Xcode (using the generate-xcodeproj command), this new built-in support both meant that apps could now easily import Swift packages as dependencies, and that package authors could directly open their projects in Xcode without first having to generate a separate project file for them.

Now, imagine if Apple took this a step further by enabling entire iOS or Mac apps to be defined as Swift packages — for example like this:

let package = Package(
    name: "MyApp",
    products: [
        .application(
            name: "MyApp",
            targets: ["MyApp-iOS", "MyApp-macOS"]
        )
    ],
    dependencies: [
        .package(
            name: "Files",
            url: "https://github.com/johnsundell/files.git",
            from: "4.0.0"
        ),
        .package(
            name: "Codextended",
            url: "https://github.com/johnsundell/codextended.git",
            from: "0.3.0"
        )
    ],
    targets: [
        .target(
            name: "MyApp-iOS",
            dependencies: ["Files", "Codextended"],
            platform: .iOS
        ),
        .target(
            name: "MyApp-macOS",
            dependencies: ["Files", "Codextended"],
            platform: .macOS
        ),
        .testTarget(
            name: "MyAppTests-iOS",
            dependencies: ["MyApp-iOS"]
        ),
        .testTarget(
            name: "MyAppTests-macOS",
            dependencies: ["MyApp-macOS"]
        )
    ]
)

Apart from my wishful .application product, and the ability to declare platform constraints for individual targets, the above is a perfectly valid Package.swift manifest. So while I’m sure that the underlying changes needed to make the above kind of feature possible would be quite substantial, it wouldn’t necessarily require a ton of changes to the package description API itself — since all of the pieces required to define targets and import dependencies are already there.

Combine that with the fact that SwiftPM is about to start supporting bundled resources (such as images, XIBs, or any other sort of custom files) as part of the upcoming Swift 5.3 release, and the package manager could become quite a capable tool for building entire (non-command line, non-server-side) applications.

While I’d expect an initial release of such a feature to just support a very limited amount of customization options and build settings, I think many teams would happily take that tradeoff in order to be able to completely say goodbye to Xcode project file conflicts, once and for all.

I would also really like to see the Swift Playgrounds app adopt SwiftPM as its module management tool. While I absolutely love the very lightweight way in which modules can be created within a playground — which I also mentioned in my review of the 3.0 version of the app — being able to instantly open a Swift package (and all of its dependencies) within the Playgrounds app would be incredible, and would make it so much easier to move code between the Mac and the iPad.

For more details on Swift Playgrounds’ module system, listen to my podcast conversation with Holly Borla and Grace Kendall from Apple, during which they went into lots of details about how the Playgrounds app was built.

Xcode on iPad

Along those same lines, I don’t think I would be able to put together any kind of WWDC wishlist without mentioning Xcode on iPad. As someone who loves working on both the Mac and the iPad (the Mac when I’m at my desk, the iPad everywhere else), I would love to be able to seamlessly move all of my projects between those two devices.

So often when Xcode on iPad is discussed, the conversation tends to end up with the question of whether either the iPad or the Mac is the best device for development, but I personally think that’s beside the point. I don’t want Xcode for Mac to be discontinued, and I don’t want to do all of my development work on the iPad — but wouldn’t it be wonderful if we were all free to choose which device to work on at any given time, without having to jump through a ton of hoops?

Will this be the year we’ll see Xcode on iPad? I honestly don’t know, but I really hope so. The current iPad Pro hardware (even the 2018 model, which I own) is more than capable of compiling and running Swift code, there’s now support for both hardware keyboards and pointing devices, and Swift Playgrounds has shown me and many others that building iOS UIs on an actual iOS device is amazing. The iteration speed between testing and interacting with a piece of UI, and making tweaks to it, when everything is running right directly on a touch-capable device, is simply outstanding.

Now, like I’ve mentioned earlier on Twitter, I don’t expect this hypothetical iPad-version of Xcode to have nearly the same amount of features as its Mac equivalent. Instead I would expect it to be a more lightweight version of Xcode focused on SwiftUI-based iOS app development, at least for the first iteration of it.

End-to-end Swift

Finally, I would love for Apple to more clearly embrace server-side Swift within Xcode and their various platform SDKs. While Apple have confirmed that they’re using server-side Swift in production themselves, and while they’ve made substantial investments in server-side technologies like SwiftNIO and Swift Crypto, I have a few wishes as to how they could take things to the next level.

One significant trend within the server-side world over the past few years has been the rise of cloud (or “serverless”) functions. It’s the idea that, rather than running any kind of server yourself, you instead just submit a piece of code to a cloud service, and then that service will automatically run that code for you and manage all required system resources — completely automatically.

Just a few weeks ago (at the time of writing), Amazon officially launched their Swift AWS Lambda Runtime, which lets developers write such cloud functions in Swift, and then deploy and run them on Amazon’s vast AWS infrastructure. That’s incredibly cool, but I’d also love to see Apple’s own take on such a system.

As an example, imagine being able to run custom cloud functions as part of CloudKit — for example in order to perform server-side validation of records that were sent from an iOS or Mac app, using the same CKRecord API that CloudKit uses on the client-side, like this:

enum ValidationError: Error {
    case invalidRecordType
    case missingIngredients
    ...
}

// This function would be automatically invoked server-side by
// the CloudKit servers, and passed any CKRecord instance that
// was submitted from a client app. The function either throws
// an error, or allows the record to be saved to the database:
func validate(_ record: CKRecord) throws {
    guard record.recordType == "Recipe" else {
        throw ValidationError.invalidRecordType
    }

    guard let ingredients = record["ingredients"] as? [String],
          !ingredients.isEmpty else {
        throw ValidationError.missingIngredients
    }
    
    ...
}

The above function uses Swift’s built-in error mechanism as part of its control flow. Check out this article for more on that topic.

While the above kind of CloudKit and iCloud customization would be incredibly cool, and enable developers to iterate on their iCloud-based code without having to ship new versions of their apps — it would perhaps be even cooler if we would be able to build completely custom function-based backends that would be automatically deployed on Apple’s servers.

Don’t get me wrong, projects like SwiftNIO and Vapor are incredible, and already enable server-side applications to be built in Swift — but my final dream (for this article) is to be able to simply write a request handler like the one below, as part of an app project, and then have it be automatically synced to an Apple-provided cloud service that would host it and run it for me:

// This function returns a note based on a parameter that was
// sent from the client, and uses Combine to facilitate the
// communication between the server and the client:
func handleRequest(_ request: Request,
                   responder: ResponderPublisher) {
    guard let noteID = request.parameter(named: "id") else {
        let error = MissingParameterError(name: "id")
        return responder.send(completion: .failure(error))
    }

    guard let data = KeyValueStore.data(forKey: noteID) else {
        let error = UnknownNoteError(id: noteID)
        return responder.send(completion: .failure(error))
    }

    responder.send(data)
    responder.send(completion: .finished)
}

While the above is a really simple example in the grand scheme of things, I think if app developers would be able to write and deploy small cloud functions using a language and set of frameworks that they’re already familiar with (such as Combine), then that could enable many kinds of apps to utilize dynamic, server-side functionality — without requiring those developers to either maintain their own servers, or rely on a third-party service.

Conclusion

So those are my biggest Swift-related dreams for this year’s WWDC. Hope you enjoyed reading this article, and if you did, then make sure to check out WWDC by Sundell & Friends — a brand new website on which me and some of my friends will cover WWDC20 in great detail all throughout next week.

What do you think? Do you share some of my dreams, or do you have any other Swift-related things that you’d like to see Apple introduce next week? Let me know, either on Twitter or via email.

Thanks for reading! 🚀