The other day, whilst preparing my submission for this year’s Swift Student Challenge, I (once again…) ran over one of the more widely known issues with Swift Playgrounds. I seemingly randomly got runtime errors such as “Abort() called”, especially when using SwiftUI for my live views. These errors, usually resulting from bugs in Swift Playgrounds itself, can often be resolved by disabling “Enable Results”. It would, however, be sort of awkward to ask those judging my playground to disable said mode themselves, I thought, and thus began searching for a way to disable this function entirely. In the end, I opted for a Swift Playground Book instead of a regular Playground as this, amongst many other advantages, allows me to use Manifest.plist-files to disable said mode. In this article, I want to give tips on how to easily migrate an existing playground to a playground book.
Using the Template
Apple provides us with a useful template through which we don’t have to create the entire directory hierarchy ourselves. To get started, you can download it yourself from Apple’s developer portal. When you open the .xcodeproj-file contained therein, it should look something like this:
As you can see, this template also provides us with a LiveViewTestApp. But I will not go into details about that one at this point. First of all, you might want to customise the metadata contained in the top-level Manifest.plist (i.e., PlaygroundBook/Manifest.plist). For instance, you might want to change the playground’s Name, or add an ImageReference to it.
Importing Playground Pages
Importing playground pages from our existing Swift Playground actually is pretty straight-forward: we can simply drag-and-drop them into the Pages/-directory of one of the template’s chapters. We, however, have to adjust a few things before the playground will be runnable. First of all, all files imported that way might still be having an old file extension (.xcplaygroundpage in my case — I created mine directly using Xcode). In that case, you have to make sure the folders name ends in .playgroundpage. Second of all, you might have to rename the page’s main file from Contents.swift to main.swift. Third of all, every playground page needs a Manifest.plist file. I could find an easy way to generate them directly within Xcode, you therefore probably have to create them manually. Their content should be something like this:
However, I just want to advise you, that these manifests are an extremely powerful tool for us playground creators! Apple gives us more details on this here.
Lastly, we need to make sure that everything we just imported is referenced correctly. Long story short, playground books are structured hierarchically — which practically means that everything must be referenced in its parent’s manifest. Most importantly for us, that means we have to make sure that all our playground pages are being referenced in our chapter’s Manifest.plist’s Pages-array. For instance:
If you changed the top-level structure (i.e., added, removed, or renamed chapters), make sure that they’re being referenced correctly in the book’s Manifest.plist as well.
If your old playground’s pages contained a Source folder, you will probably encounter an error saying you have to use modules instead. In order to do so, you’ll probably have to restructure your code a bit. The prebuilt template already comes with two modules which you can find in the Modules/ directory (a module essentially is a directory ending with .playgroundmodule, containing a source directory, containing .swift files). You can either use the built-in ones or add your own one by creating a module using the directory structure mentioned above. Having moved all Swift files from a page’s old Sources/ folder to a module, you just have to import the module within your code. All modules are available for import to your swift code by their respective directory name without the trailing .playgroundmodule (e.g., BookCore.playgroundmodule → import BookCore).
“Compiling” the Playground Book
Once finished, you are ready to compile your playground book. If you used Apple’s template, you already have an Xcode build target for the final .playgroundbook file.
Clicking Run now results in a .playgroundbook-file being built. You can find that file in your project’s Products/ folder. Using Control-Click → Show in Finder → Share you can for instance air-drop it to an iPad.
Disabling the “Enable Results”-mode
Considering my introductory problem: having moved to a playground book, the solution is quite straight-forward at this point. We can add the PlaygroundLoggingMode key to a page’s Manifest.plist and set its value to Off. That’s all! Said mode will automatically be disabled and cannot be enabled manually anymore 🙂.
A Huge Disadvantage
I nonetheless want to note a huge disadvantage of using a Playground Book at this point: Xcode doesn’t seem to like them — code highlighting is buggy, and code completion usually doesn’t work at all! If you heavily rely on such features (let’s be honest — most of us do… 😉), you’re probably best off finishing your project as regular playground first, and then migrate to a playground book. Alternatively, you could use an external editor, too.