Since the Swift Package Manager (Swift PM or SPM) was introduced in late 2015 it has seemed like a natural fit for Xcode and SPM packages to work well together at some point in the future. At WWDC 2019, Apple announced that future was arriving in Xcode 11.
Xcode 11 provides two new ways to work with Swift Package Manager packages:
Open an SPM package in Xcode
Add SPM package dependencies to an Xcode project
These two new capabilities join a long-standing SPM feature:
Generate an Xcode project for an SPM package
Each of the these approaches are different both conceptually and in the nitty gritty details of what files they put where.
Open an SPM Package in Xcode
In Xcode 11, you can open a Swift Package Manager package directly in Xcode without needing a .xcodeproj Xcode project file.
Conceptually, you are working in a Swift Package Manager-centric world with the added ability of using Xcode to edit, build, and test your Swift package.
Note that this does not give you all of the settings and flexibility of an Xcode project. You cannot specify build phases, include resources, do code signing for an app, or any other functionality that is not currently supported by Swift Package Manager.
But being an Xcode project is not the purpose of this particular feature. This feature is all about using Xcode as an IDE for Swift PM packages.
What happens on disk?
Opening a package in Xcode adds a hidden .swiftpm/xcode directory to the package.
As you might guess, the xcode directory contains files Xcode uses such as a package.workspace file containing information about the workspace and xcuserdata and xcshareddata directories.
The .gitignore file generated when creating a new package includes xcuserdata as ignored. You will likely not want to add these files to your git repository. The files in xcshareddata on the other hand include shared schemes generated by Xcode which you may want to check into git to share among team members.
You will probably want to use the same policy of which Xcode-centric files to check in or ignore that you are using for Xcode projects.
The checked-out dependencies and build products are stored in the hidden .build directory, just like building the Swift package using swift build on the command line.
So, with a fairly small footprint of additional files, you can now use Xcode for Swift PM package development.
Add SPM Package Dependencies to an Xcode project
Also in Xcode 11, you can add Swift Package Manager packages as dependencies of an Xcode project.
Conceptually, you are working in an Xcode project-centric world with the added ability of having Xcode manage dependencies on Swift packages.
You specify the source URL and version of the package you want to use in your project. Xcode will automatically download the correct package version and any dependencies of that package. The dependencies are recorded in your Xcode project file, similar to dependencies on frameworks and libraries.
This is a significant addition. For the first time, Xcode has a native mechanism for managing and updating dependencies.
Developers in the Xcode ecosystem have traditionally turned to third-party solutions such as CocoaPods or Carthage for this functionality, or used git submodules in projects to combine code from different git repositories.
Xcode 11 opens the door to dependency-handling workflows that are actively supported by Apple and its tools.
But I don’t use Swift yet!
Even if your projects are not in Swift yet, you can create SPM packages with targets and products of C-based languages including Objective-C. The only Swift that must be in a package is the declarative Package.swift manifest file.
What happens on disk?
Adding SPM package dependencies to an Xcode project will add a Package.resolved file to the project’s workspace at xcshareddata/swiftpm. This file contains the resolved versions of each dependency. This file is intended to be included in source control so team members and continuous integration systems can use the same dependency versions.
As you might expect, the package dependencies will be referenced in the project’s project.pbxproj file.
There are no additional changes to the Xcode project and no hidden directories added. Everything else, including the downloaded package sources and build artifacts are located in the Xcode derived data directory for that project. The SourcePackages directory in the project’s derived data contains the checkouts and repositories for the Swift packages.
In addition to adding remote package dependencies to the project, Xcode will also recognize local package dependencies. This is useful, for example, if you are developing an app and a supporting package at the same time.
The addition of Swift package dependency management in Xcode gives you a powerful new option in structuring your projects’ dependencies.
Old Original SPM-Generated Xcode Project
Since the early days of the Swift Package Manager, you could generate an Xcode project for a package with the command swift package generate-xcodeproj.
This feature has always had limitations and drawbacks. With the new capability of opening a package directly in Xcode, you should never need to use this feature. But, it is still a temping option when looking at swift package help, so it might be helpful understanding why you don’t want to use this.
The SPM-generated Xcode project is intended as a convenience to use Xcode to view and edit your package. It is not meant to be a long-lasting resource.
If you make changes to the package’s manifest, add or remove dependencies, or make any significant changes, you need to regenerate the Xcode project. It is intended to be a transient resource, a convenient throwaway project to allow you to use Xcode to edit and build the package.
Because of this, the generated Xcode project was not intended to be shared or checked-in to source control. This is confirmed by looking in the .gitignore file automatically generated by SPM where /*.xcodeproj is on the list of files to be ignored.
The generated Xcode project stores some items within the xcodeproj directory including an Info.plist file per target in the package.
If your package has any C-based library targets, (for instance if you are exposing an existing C library to Swift), then the generated Xcode project contains a directory GeneratedModuleMap which contains a module map for each C-based target. The module map file contains a hard-coded path which includes the current user’s home directory. This makes the generated Xcode project decidedly un-shareable.
I am unable to think of a good use case for a generate Xcode project file now that Xcode 11 has the ability to open Swift packages directly. This functionality now seems obsolete.
Summary
With the introduction of Xcode 11, there are now three main ways to work with Swift Package Manager packages in Xcode:
Swift Package Manager-centric
Use Xcode as an IDE for Swift PM packages. No Xcode project required.
Xcode project-centric
Add Swift PM packages to an Xcode project. Xcode manages the dependencies.
Swift Package Manager generated Xcode project
Don’t use any more. Just open the package directly in Xcode 11.
The WWDC 2019 session Adopting Swift Packages in Xcode contains a number of demos showing how to use Xcode with Swift PM packages and is a good resource for getting started.
Xcode 11 makes great strides in working with Swift PM packages in two complimentary ways. •
The last week and a half or so, I’ve been driving up and down the East Coast. (Hello I-95, my old friend. I’m paying tolls on you again.)
My trip included attending the 90th birthday of a family member in Virginia, visiting my sister in NJ, visiting a friend in Delaware, and then celebrating the birthday of my friend Larry Noto in Maryland. I also did an open mic night at Larry’s music store Music Land and saw Larry’s stand-up act , opening for Jon Lovitz.
While driving, I was thinking about a little piece of an app I’m working on. I write an integer out into a URL as a string and then read the integer back in when I interpret the URL—nothing earth-shattering.
My thoughts turned to ways to make that URL shorter and a bit less ugly, with the premise that longer URLs are uglier URLs.
As I made my way down the road, it occurred to me, a hexadecimal string would certainly be more compact. But then, if base 16 is good, base 32 would be even better. Two characters in base 32 could represent 1024 values instead of 100 in base 10. Three characters could represent over 32K values instead of 1000.
So, in the end I was looking for:
Small encoding. A way to encode an integer as a string that uses as few characters as possible.
A ‘URL-ready’ string. The resulting string should need no further URL encoding for things like spaces.
Easy to implement. The minor improvement is not worth a lot of engineering effort to implement or maintain.
Enter the Swift Standard Library
One drawback of a road trip is the inability to write code or even peruse documentation while driving. After arriving at my destination, I did some poking around and found these in the standard library:
An initializer for Int: init?(_:, radix:)
And one for String: init(_:, radix:, capitalized:)
In both initializers, the radix has a default value of 10 but can handle everything from base 2 to base 36.
Base 36?
In this base 36 encoding, the digits 0-9 and the letters a-z are used in the string representation. The decimal number 35 is z, the decimal number 940 is q4.*
Using a radix of 36 gooses the values representable by a two character string up to 1296, and by three characters up to over 46K.
And, as it turns out, I was already using those initializers with the default parameters to encode and decode the integer.
I ended up factoring out those calls into a few extensions on URL and URLComponents, but, conceptually the answer was simply to move from:
let stringValue = String(integerValue)
let int = Int(stringValue) ?? "0"
to
let stringValue = String(integerValue, radix: 36)
let int = Int(stringValue, radix: 36) ?? "0"
So, the solution met all of my criteria. I updated the code in my hotel room.
The Old Coldness
Checking on swiftdoc.org, it looks like this functionality has been in Swift since at least Swift 1.2.
This made me realize the even with all of the new things introduced with each release, Swift and the standard library had a lot of nice functionality from the beginning.
Some of my drive time thinking was about solving a programming problem. But then afterwards, my thoughts progressed to how we are understandably drawn to the brand new features, but that sometimes a piece of API that has been around for years can be brand new to you, and that’s just as exciting and delightful a discovery. •
June 2019 has me feeling like a kid in a candy store.
I’m remarkably excited by the variety of things that are catching my interest and attention this month—so much so that I’m finding it difficult to decide what to do next.
A large part of that is due to all of the announcements at WWDC—but that is not all.
My week following the developer conference was a flurry of watching session videos and digging into things. But WWDC was not the only thing going on in the world in a few weeks back. On May 31st, Star Wars: Galaxy’s Edge opened at Disneyland.
Star Wars: Galaxy’s Edge
As a big Disneyland and Star Wars fan, had it been any other time of year, I would have tried to be there opening weekend. However, just days before WWDC, with a big LIVE near WWDC show to rehearse and prepare for, there was no way I could make it down to Anaheim.
I didn’t have to wait long though. Last weekend I had the chance to visit Galaxy’s Edge at Disneyland. I feel like they’ve done an amazing job of creating a place that feels very much a part of the Star Wars universe, even though it a brand new location not depicted in any of the movies. My inner nine-year old found it very satisfying to fly the Millennium Falcon, build my own lightsaber, and yes, drink some blue milk.
Combine Framework and Foundation
On Monday I headed home from Disneyland as Beta 2 dropped for Xcode 11, iOS 13, macOS 10.15, and all the rest.
The new beta includes Combine framework support for Foundation classes. So, it just became possible to write code to explore the same sort of data publishing pipelines that were presented in the Combine sessions at WWDC. This includes publishing notifications, properties, and timers.
So, another whole aisle of candy just opened up and I’ve spent most of the week catching up from my trip, rewatching Combine videos from WWDC, and playing around with Combine code.
So far, I am feeling the same sort of enjoyment in writing Combine code as I have had writing SwiftUI code. The main area of frustration I am finding with Combine is that the session videos are the primary place to see Combine sample code. (If I am missing a trove of Combine sample code from Apple – please let me know on Micro.blog or Twitter!) So, I’m finding that anything not covered in those sessions takes bit of trial and error to figure out.
Along the same lines, the code in the sessions often show the path from publisher through operators to subscriber, but don’t necessarily talk about who should be holding onto the publisher or the cancelable item returned from the subscriber, or exactly when it makes sense to set them up. It would be great to see more Combine framework sample code from Apple showing it in integrated into an app project, especially traditional UIKit and AppKit apps.
Toy Story 4, Forky, and WALT
Today I put the Combine framework aside for a few hours to go see Toy Story 4. Every time Pixar announces a sequel I worry that this is the one where they will jump the shark in the franchise. I am very happy to say that I really enjoyed Toy Story 4. I found Forky to be absolutely delightful!
If you know me for any length of time, you will soon discover that I am a big fan of Disney and Pixar animation.
The first iOS app I wrote is WALT: Watched Animation List Tracker. It’s not a commercial success by any means, but it’s an something I wanted to have in the world. It lists over 650 short and full length animated films from Disney Animation Studios and Pixar Animation Studios and lets you check off the ones you’ve watched.
I wrote about the creation of WALT shortly after I released it back in 2012. (Was that really about seven years ago? Wow!) A heads-up if you are thinking about paying 99 cents for the app, I do intend to make it a free app and add a tip jar. However there are many other things ahead of that on my to-do list, so I can’t tell you exactly when that will happen.
As mentioned in that original article, one inspiration for WALT was the The Walt Disney Family Museum (WDFM) in San Francisco. I have been a member since it opened ten years ago. The location is beautiful, in the Presidio with a view of the Golden Gate Bridge. And I find the museum and the story that it tells to be inspirational.
Fantasia Talk at The Walt Disney Family Museum
In addition to the exhibits at the museum, one of the things I enjoy most are the programs that they have throughout the year. In the past I have seen many great talks that speak to the creative process. For instance last year, I saw Brad Bird speak about his experiences working with classic Disney animators. I’ve seen animators Andreas Dejas and Floyd Norman talk about their time at Disney. And I’ve had the chance to see original Imagineers like Alice Davis and Marty Sklar.
Tomorrow I’ll heading up to San Francisco to see a talk by composer Fabrizio Mancinelli called The Beauty and Legacy of Fantasia. I’ve always enjoyed and been fascinated with the way animation and music can work together to achieve an effect and look forward to hearing what I believe will be an interesting perspective.
That’s A Lot Of Candy
In feeling like a kid in a candy store, June 2019 is not just some quaint little corner candy store. It’s been a giant store with aisle after aisle of classic candies, exotic candies from faraway places, and brand new candies you had never even heard of before.
With all of this intellectual and experiential candy, I hope I do not get the psychological equivalent of a bellyache. But even if I do, it has been a very memorable and enjoyable month so far. •
I began investigating SwiftUI to see if it is indeed the shortest path to a great app. Since then, I committed an update to the MemeMaker project that makes the initial interface a list of examples. I was experimenting with passing a different View into each row as the destination of the row’s NavigationButton, rather than hard-coding the destination.
I found that you can’t just make a property of type View. I believe that is because it uses Self within its declaration of the body property. And so the compiler dutifully complained.
Seeing the type-erasing AnyView type in the documentation, I wrapped everything in AnyViews to get it all working.
I got some feedback from Matt Ricketson on Twitter suggesting I use generics here instead.
This is a great example for trying out generics instead of AnyView. It will make your NavigationButton even simpler, and in general will give better performance. AnyView should be a tool of last resort.
With the SwiftUI and Combine frameworks using generics so heavily, I need to develop my intuition about generics beyond arrays and dictionaries. I also really need get better at reading declarations that are chock full of generics.
Fortunately, I think the two go hand in hand.
When Swift first arrived, I found reading optionals in code to be difficult. But AppKit and UIKit development meant using them immediately. I dug in to understand them as best I could. I even wrote a song about it. And now reading and writing code with question marks and exclamation points seems natural, not baffling.
I’m hopeful that as I use SwiftUI and Combine that I’ll refine how I think about generics as well.
I’m also curious. Are there ways that you think about genetics that have made them more understandable for you? (Not so much the syntax, more so the zen of generics) Any articles that you’ve found particularly useful?
I’d love to hear. Please send any of your generic thoughts or thoughts on genetics to @jamesdempsey at Micro.blog or Twitter.
Also, if you are ever writing about generics on an iPhone: BEWARE! Autocorrect really wants to replace ‘generics’ with ‘genetics’! •
In my previous post, I described the JDBP band app I want to build and the technologies introduced at WWDC 2019 that I think might make it much easier to create.
Part of the process is exploring these new technologies and SwiftUI is first on my list.
As I’m playing with SwiftUI, I’m not thinking too much about the app I want to build. For me, and probably many others, my first step beyond watching videos and walking through tutorials is to play with it, use it to build a few small throwaway apps, and try to develop as good a feel for it as I can in a short period of time.
I’m not at a point where I can nitpick over whether I agree or disagree with this or that design choice in the framework. I definitely don’t know it well enough yet.
Currently, I’m in the process of building up my mental model of how all of this works. This also includes mentally diffing that model with my existing mental models of AppKit and UIKit.
That’s a lot of brain cycles. This is going to take a while and is probably also going on as a background process as I sleep.
I found these two sessions really helped me begin to build that mental model of the frameworks beyond tutorials and demos:
I am sure I will watch them multiple times. I also hope we get more documentation, more tutorials, and maybe even more WWDC-like videos from Apple. I feel like what we saw in sessions at WWDC and in the tutorials only scratch the surface of SwiftUI.
How Does It Feel?
I don’t have enough experience with the framework yet to declare that SwiftUI is the shortest path to great apps.
But I’m sure having a blast playing with it!
I haven’t felt a sense of joy and exuberance like this about UI programming for a very long time.
Will that sense of joy fade as I start trying to use SwiftUI for a ‘real app’?
Certainly the excitement of novelty will fade as it becomes more familiar. For other aspects, time will tell, but for now I’m just going to enjoy the ride.
Joy
For me, there’s joy is in how quickly you can compose a complex view—even a live data-driven view—without much code at all. There’s joy in the tooling and preview mechanism, which is flexible and fairly responsive.
And there’s joy in the fact that the views that you compose are well-behaved.
All those things that may have caused you to breathe a tired sigh in the past—things you knew you should or must support, like Dynamic Type, Right-to-Left UIs, Dark Mode and more—now happen automatically and correctly.*
The framework and tools seem to be very thoughtfully designed, in terms of the functionality that is provided, but also in the unified way that things fit together, scaling from structural components like navigation to views and controls, all the way down to shapes, paths, and graphics operations.
MemeMaker
Yesterday, I posted a meme that seems to have gotten a few amused smiles:
Meme Maker is a not-particularly-functional app created by someone on their couple of days using a new technology:
You can’t edit the text except by editing the code
You can’t different image unless add other images to the project
You can’t export or share the meme
The app composes some text over an image in a few different ways and then you can take a screenshot of the result to share if you want to.
But it also shows a few things people might find interesting:
The main list uses AnyView to pass destination view into row
The Overlay example uses the overlay modifier to overlay the text on top of the image. Probably the cleanest solution
The ZStack example shows my original example using nested zstacks to pin text to top and bottom of image
The Text Gone Wild example shows what happens when the text is allowed to spread out as far as it can
All examples show using a named font instead of a semantic font
All examples show adding a shadow to text and using a non-named color
So, I put it out there if you want to check it out.
Feel free to download it or fork it and use it as a starting point for your own explorations. If you discover alternate ways to achieve the same result or any other cool things, let me know at @jamesdempsey at Micro.blog or Twitter. •
Feedback
I’m also trying to post a record of feedback I’ve filed. If anything sounds good to you feel free to file similar feedback.
Feedback Filed:
FB6145912 Would love an ‘Embed In…’ menu option when writing SwiftUI code
FB6145990 Would be great to have option to refactor a View directly into a new SwiftUI file
FB6139401 Framework Reference docs should include a Symbol Index Oh how I miss having that big, high info density index of Class / Struct / Protocol / Function symbols!
*And you didn’t breathe that heavy sigh because you didn’t want your app to have that functionality—it was because it takes a chunk of time and work to do and do correctly—time you wish you could spend improving the core functionality of your app or maybe even spending with family and friends. ⏎