The Xcode 11 and Swift Package Combo Platter

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.

Icons for Xcode, a Swift Package Manager package, and an Xcode project

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, justconvenience 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. •

Breakpoints Recap WWDC 2014

There was no WWDC ticket for me this year, but it was still a very enjoyable and busy week for James Dempsey and the Breakpoints. Here are some of the highlights from last week in San Francisco.

(Interested in the soon-to-be-released James Dempsey and the Breakpoints album?
Sign up for email updates so you don’t miss out on the fun!)

NeXTEVNT Cartoon Art Museum Fundraiser

In its third year, this fundraiser celebrates the heritage and history of NeXT, featuring black hardware as well as OPENSTEP and NeXTSTEP running in virtual machines. Even more fascinating is meeting up with folks who lived and breathed this platform from its early days—building apps with the frameworks that would evolve into Cocoa and Cocoa Touch.

As part of the evening’s entertainment, we played a short set of songs in support of the Cartoon Art Museum. If you are a fan of any sort of comics, cartoons, animations and the like, check it out next time you are in San Francisco. If you couldn’t attend the event during WWDC, you can still donate or join as a member.

 

LIVE near WWDC 2014

We had a great time on Wednesday night at 50 Mason Social House. The house was packed as Breakpoints from six different cities in five different time zones across two continents took to the stage to perform a show chock-full of Cocoa-inspired songs.

The evening served up an acoustic guitar sampler with a flight of Breakpoint guitarists—Nathan Eror (@neror) of Martian Craft, Jonathan Penn (@jonathanpenn) of Cocoa Manifest, and Ben Scheirman (@subdigital) of NSScreencast.

The show marked the debut of The Breakpoint Horns with Sam Davies (@iwantmyrealname) of Shinobi Controls on trombone and Daniel Pasco (@dlpasco) of Black Pixel on trumpet playing on Modelin’ Man.

(Any tenor sax players out there for next year? Please let me know.)

The talented Mr. Pasco also played electric guitar on that modern tale of momentary loss and redemption, Almost Dropped My iPhone. Conditional Breakpoint Uli ‘Object Alloc’ Kusterer (@uliwitness) of Elgato joined in with The Liki Song chorus. And of course, slide-advance keyboard legend Victor Alexander (@victoralexander) was on hand to keep that space bar hoppin’.

Thank you to all of the Breakpoints and also a big thanks to: Luke Scholefield (@lukescholefield), Adam Tow (@atow) and Rae and for taking photos and video; Daniel Steinberg () for recording sound off the board; and James White (@thecolourfool) for running the merch table.

(For more fantastic photos of the show—check out Adam Tow’s photo journal.)

Finally, an enormous thanks to everyone who came out to the show — your support is what keeps this going.  We had a great time this year and hope you all did too!

 

A Look Back at Alt Conf

On Friday, I presented A Look Back—the closing session for Alt Conf 2014.  With the surprise announcement of Swift earlier in the week, the talk took a look back to the beginning of the Objective-C era at Apple, tracing how technologies of that time have evolved into the environment we use today.  To accompany this look back, the talk also featured the first public preview of tracks from the soon-to-be-released James Dempsey and the Breakpoints album.

James Dempsey at podium with blurred hands applauding

James wraps up AltConf 2014 with ‘A Look Back’
Photo by Daniel Doubrovkine (@dblockdotorg)

Thank You

The technology announcements of WWDC 2014 will have repercussions for us as iOS and Mac developers for many years to come.

Beyond learning about new technologies, the week gives us a chance to gather together and talk, to share ideas, some laughs and perhaps one too many drinks.

Thank you so very much to everyone who came out to see the talk and performances. Your support and feedback is greatly appreciated and means a lot to me—it was fantastic to meet so many folks this year.

With WWDC 2014 now in the past, it is time to turn my attention to finishing up the album and getting it out into the world.  Someone we are all familiar with said “Real artists ship” and that is my next order of business. •

(Interested in the soon-to-be-released James Dempsey and the Breakpoints album?
Sign up for email updates so you don’t miss out on the fun!)

Get Email Updates Button

New Breakpoints Song at Renaissance!

James Dempsey and the Breakpoints will be debuting a new song at the Renaissance conference later this month. The song will be part of a noon performance on Wednesday, January 23rd, which will include old favorites along with the new single.

To find out more, I sat down with myself for a fake interview:

Can you tell us a little about the new song?
The new song has a different intent than all the others we’ve done.  Previous songs aimed to teach as well as entertain. This new song keeps to a technology theme, but is meant entirely in good fun.

Why debut the song at the Renaissance conference?
The conference brings together all iOS app builders—developers, designers and business people. It seemed the perfect place to introduce the first James Dempsey and the Breakpoints song that doesn’t require working knowledge of Objective-C or design patterns to fully enjoy.

Will the new song be available on iTunes?
Yes. The Breakpoints have been back in the studio and we’re in the middle of production. We are on track for the single to drop on iTunes as close to the live debut as possible.

What’s the difference between playing live and being in the studio?
Our live performances are acoustic, laid-back and lots of fun—we keep it simple in a live setting. In the studio, we can get more complex with additional tracks and instruments.

How’s the album coming along?
Last year we started recording a decade’s worth of technology songs. We found a great studio, got rolling on recording and laid down a lot of tracks. With this new song, we are back in the studio and working towards finishing the album.  Follow this blog or @jamesdempsey on Twitter to find out the moment there is more news about the upcoming album.

Can you tell us any more about the new song?
After working at Apple for fifteen years, it feels strange to say even this much about something that isn’t released yet. I can say that we’ve definitely enjoyed working on the new song, we think it will bring a smile to people’s faces and we’d love to have as many folks as possible join us for the live show at Renaissance. •

The Renaissance conference is January 21-23 in San Francisco.  Tickets are available here.

To save an additional $100 on registration for Renaissance contact me for a discount code.

Moving to new Objective-C literals

Last week, I moved one of my projects over to use the new Objective-C literals for NSNumber, NSArray and NSDictionary as well as the new syntax for boxing expressions into NSNumber and NSString objects.  Here are a few comments on how it went.

In a nutshell, the new language features allow code like [NSNumber numberWithInteger:7] to be replaced by a more compact syntax like @7.  The LLVM site has a full description of the new syntax and usage.

Refactoring in Xcode

I ran the ‘Convert To Modern Objective-C Syntax’ refactoring tool in Xcode 4.4 to do the conversion.  There is no option to choose which modern syntax features you wish to adopt before the conversion begins, but in Xcode 4.4, you can choose diff by diff which changes you wish to keep.  Xcode seems to think my Objective-C syntax is already modern enough in other respects, since the only changes the refactoring made was to move to Obj-C literals.

Even if you want to introduce the new literals into your code manually, you might find it interesting to run the refactoring tool just to browse through its proposed changes.  You can cancel the changes rather than apply them, but just by reviewing the proposed diffs, you might see use cases for Obj-C literals that may not have occurred to you.

There were more places than I was expecting where my code creates NSNumber instances from integer expressions and enums.  Also, before running the refactoring tool, it had not occurred to me how often the expression being boxed would just be a single variable holding a scalar value.

So there were numerous places where the updated code did something similar to the following:

NSInteger myValue = 0;
// Do some stuff that changes myValue
[myArray addObject:@(myValue)];

Before doing the conversion on my own code, I definitely underappreciated the power and usefulness of boxed expressions.

Overall, I found the refactoring in Xcode 4.4. to be easy and straightforward.  The Xcode project I converted was a medium-sized Objective-C project using the iOS 5.1 SDK.

A crashing issue to watch out for

There is a potential crashing issue that I ran into that you should be aware of.  In one spot, the code was relying on a nil value terminating the list of arguments to create an array.  So something like:

-useRequiredValue:(id)requiredObj optionalValue:(id)optionalObj {
   NSArray *array = 
         [NSArray arrayWithObjects:requiredObj, optionalObj, nil];
   // Do something useful with array
}

The method +arrayWithObjects: stops processing arguments when it hits the first nil argument.  The code above relies on that fact to create a one-object array when optionalObj is nil, and a two-object array when optionalObj exists.

The conversion changed the array creation to:

NSArray *array = @[requiredObj, optionalObj];

With array literals, relying on a terminating nil does not work.  Behind the scenes, a literal NSArray is created with +arrayWithObjects:count: which requires non-nil values.  So, after converting to Obj-C literals, an exception was thrown whenever the optional argument was nil.

A similar issue arises with dictionaries if you are relying on early nil-termination with +dictionaryWithObjectsAndKeys: and then move to use an NSDictionary literal.

Note that this issue is not flagged by the refactoring tool or the static analyzer, so it is something to watch out for when converting to use Objective-C literals.

To address the issue, the options are either to revert to the previous code or change the code to something else.

I changed the code to something like this:

NSArray *array =
     (optionalObj != nil) ? @[requiredObj, optionalObj] : @[requiredObj];

I decided to stop using the ‘early nil’ approach for a few reasons.  The first is that I know I will be tempted to change that line of code to use a literal array every time I look at it, which will reintroduce the crash.  I could guard against that by adding an emphatic comment explaining the situation, to prevent myself from changing that line of code.  So, everytime I look at the code, I’ll be tempted to convert the line of code, and then have to read about why I can’t convert that line of code.

It seemed more maintainable to move to a different way of doing the same thing.  In addition, the new code is less tricky/clever than the old code and more explicit about what the result will be; no comment is needed.  I am a big fan of well-commented code, but I’m also a fan of code that is obvious enough that the code can clearly speak for itself.

Readability

In most cases, the new literal syntax leads to code that is both more compact and more readable.  In the above example, the new code is not much more compact than the original code, but, the intent is clearer, which I find more readable.  With numbers, ‘@3.6’ is more readable and compact than ‘[NSNumber numberWithFloat:3.6]’.  For arrays and dictionaries, I find that my eyes are not yet parsing literal array and dictionary creation as smoothly as more familiar Objective-C code, but I suspect that will change as I use and see the new constructs more often.

Boxed expressions may cause readability to suffer to some degree.  When you encounter something like ‘@(someVariable)’, it is ambiguous whether you are creating a number or string.  You need to know the type of the expression to know for certain.  In practice, descriptive variable names should make this less of an issue.

I find the code becomes less readable as the boxed expression inside the parenthesis becomes more complex and when Objective-C literals and boxed expressions are combined and nested.  We are moving from code that had giant billboards of [NSString stringWith…  or [NSNumber numberWith… proclaiming just what is being creating, to code which is definitely more compact, but may also be more difficult to read.  For example:

@{ValueAverage : @((self.currentValue - [self.relatedObject
currentValue]) / 2), BoundaryValues : @[@(self.maxValue), @(self.minValue)]}

Even after such a short time using the new syntax, I find that on balance, the literals and boxed expressions make for more readable and compact code, with a few cases where readability seems to suffer a bit.  It is also early in the game, in terms of using the new syntax on a day to day basis.  My opinion will continue to evolve as I use the new constructs more.

Backward binary compatibility and a little BOOL wrinkle

The new Objective-C literal functionality is handled in the compiler, so you must be using a recent version of the LLVM compiler to use this syntax.  Since the compiler generates code that uses existing object creation methods, the code you write and compile can run on previous versions of OS X or iOS.

So, even if you are targeting releases of your app on OS versions earlier than OS X 10.8, or iOS 6, you can use the new literals along with the new version of the tools.

I did encounter one wrinkle with BOOL literals.  To enable the compiler to properly deal with @YES and @NO to represent NSNumber BOOL values, two new language keywords were added to the Objective-C headers.

The iOS 5.1 SDK does not include these new keywords.  So, if you are using Xcode 4.4 and the iOS 5.1 SDK, you need to ‘box’ the BOOL values as expressions to compile: @(YES) and @(NO).

The Mountain Lion 10.8 SDK does have the new keywords as will SDKs moving forward, so this is just a minor transitional oddity.

Conclusion

Overall, I think the new Objective-C literals and boxed expressions are an excellent addition to the language.  I found converting to the new syntax using Xcode 4.4 refactoring to be a smooth process.  The only real bump I hit was in code where I was relying on early nil termination of arguments when creating an array.  The other wrinkle I encountered was the need to box BOOL values using Xcode 4.4. and the iOS 5.1 SDK.   I’m looking forward to using these new language features moving forward.